JavaプログラマーからみたVala (3) クラス
原典は、“Vala for Java Programmers”(2011年3月13日取得)です。
- JavaプログラマーからみたVala (1) ソースコード
- JavaプログラマーからみたVala(2) 型
- JavaプログラマーからみたVala (3) クラス
- JavaプログラマーからみたVala (4) クラス②
- JavaプログラマーからみたVala(5) 通知
- JavaプログラマーからみたVala(6) 引数
- JavaプログラマーからみたVala(7) その他
- WindowsでValaを動かす
******************************
継承
Javaの場合: extendsとimplementsを使用します。
public class Demo extends Foo implements Bar { public Demo() { super(); } }
Valaの場合: コロンとそれに続くカンマ区切りリストであらわします。このリストには親クラスもインターフェースもともに含まれます。
public class Demo : Foo, Bar { public Demo () { base (); } }
Vala言語では親クラス(super)を基本クラス(base)と呼びます。
オブジェクトベースクラス
Javaの場合: すべてのクラスはObject(java.lang.Object)から暗黙的に継承します。
public class Foo { // ... }
Valaの場合: Object(Glib.Object)からの暗黙的な継承は行われません。
public class Foo : Object { // ... }
Glib.Objectからの継承を行わないとどうなるのでしょうか? このような場合、そのクラスは若干軽量になる一方、プロパティ変更通知(property change notifications)などのいくつかの機能を欠いたものになります。そしてこのクラスは共通基本クラスを持たないことになります。たいていの場合、Glib.Objectからの継承は必要となるでしょう。
メソッド多重定義
Javaの場合: 以下の例のようにメソッドの多重定義(overloading)が行えます。
public class Demo { public void draw(String text) { } public void draw(Shape shape) { } /* メソッドのオーバーロード、 そしてより引数の数の少ないメソッドによる、 引数の数の多いそれの利用*/ void f(int x, String s, double z) { } void f(int x, String s) { f(x, s, 0.5); } void f(int x) { f(x, "hello"); } }
Valaの場合: メソッドの多重定義はできません。別名を付けるか、引数にデフォルト値を指定することで代わりとします。
public class Demo : Object { public void draw_text (string text) { } public void draw_shape (Shape shape) { } /* 引数にデフォルト値が指定されたメソッド */ void f (int x, string s = "hello", double z = 0.5) { } }
Vala言語がメソッド多重定義の機能をサポートしないのは、Valaのライブラリが、C言語コードからアクセス可能であるよう意図して記述されているからです(意訳)。
コンストラクタ多重定義
Javaの場合: コンストラクタの多重定義ができます。
public class Foo { public Foo() { } public Foo(int foo) { } public Foo(String bar) { } } new Foo(); new Foo(42); new Foo("hello");
Valaの場合: 多重定義ではなく、名前付きコンストラクタ(named constructors)を使用します。
public class Foo : Object { public Foo () { } public Foo.with_foo (int foo) { } public Foo.from_bar (string bar) { } } new Foo (); new Foo.with_foo (42); new Foo.from_bar ("hello");
コンストラクタ連鎖
Javaの場合: “this()”記法で実現します。
class Foo { public Foo() { this("bar"); } public Foo(string bar) { } }
Valaの場合: “this()”記法もしくは“this.コンストラクタ名 ()”記法で実現します。
class Foo : Object { public Foo () { this.with_bar ("bar"); } public Foo.with_bar (string bar) { } }
オーバーライド
Javaの場合: すべてのメソッドはデフォルトで仮想メソッド(訳者:C#で導入された概念。オーバーライド可能なメソッド)です。オーバーライドを阻止するにはfinal修飾子を使用します。
public class Super { public int myMethod(int x, int y) { } public final void anotherMethod() { } } public class Sub extends Super { @Override public int myMethod(int x, int y) { super.myMethod(x, y); // ... } }
Valaの場合: すべてのメソッドは、デフォルトで非仮想メソッド(オーバーライド不可能なメソッド)です。オーバーライドを可能にするには明示的にvirtual修飾子を使用する必要があります。 他方、Vala言語には@Overrideアノテーションの代わりにoverride修飾子があり、この修飾子の使用は任意ではありません(強制です)。
public class Super : Object { public virtual int my_method (int x, int y) { } public void another_method () { } } public class Sub : Super { public override int my_method (int x, int y) { base.my_method (x, y); // ... } }
アクセス修飾子
Java | Vala |
---|---|
public | public |
protected | protected |
package-private (デフォルト) | internal |
private | private (デフォルト) |
クラスメンバーのアクセスはデフォルトでprivateですが、publicアクセスのメンバーと対称的にさせるために、明示的にprivate修飾子を使用することもできます。
インターフェース
Javaの場合: インターフェースのメソッドは暗黙のうちに抽象メソッドです。
public interface Foo { public void foo(int i); public int bar(String s, double d); }
Valaの場合: abstract修飾子は明示的に使用する必要があります。
public interface Foo { public abstract void foo (int i); public abstract int bar (string s, double d); }
なぜでしょう? それはVala言語におけるインターフェースが非抽象メソッド(実装をともなうメソッド)をメンバーとすることができるからです。つまりVala言語のインターフェースは、いわゆるミックスイン(mixins。限定的な多重継承)を実現するために利用できるのです。
Vala言語におけるインターフェースは、──例えばファクトリーメソッドのような──staticメソッドを持つこともできます。
Javaの場合: インターフェースは継承可能です。
public interface IfaceA { public void methodA(); } public interface IfaceB extends IfaceA { public void methodB(); } public class Demo implements IfaceB { public void methodA() { } public void methodB() { } }
Valaの場合: インターフェースは必要条件として働きます。
interface IfaceA : Object { public abstract void method_a (); } interface IfaceB : Object, IfaceA { public abstract void method_b (); } class Demo : Object, IfaceA, IfaceB { public void method_a () { } public void method_b () { } }
Valaでは、インターフェースは他のインターフェースから継承できません。しかし他のインターフェースを必要条件として宣言できます。これによりおおよそ同じことを実現できます。インターフェースは、インターフェースだけでなくクラスも前提条件として宣言することができます。これにより、あるインターフェース(を継承したあるクラス)のインスタンスが、Glib.Objectのサブクラスでもあることを保証することができます。この事実──インターフェースは他のインターフェースのメンバーを継承できない──は、ほとんど技術的なちがいでしかありません。実際のところVala言語のインターフェースのシステムは、Javaにおけるそれと同じように働きます。ただ、Valaにおいてはクラス継承を必要条件とするという機能もある、ということです。
******************************