2012-02-08 7 views
1

私は、部分的にScalaで、一部はJavaで、次のコードを持っている:スカラ:継承されたインターフェイスメンバの初期化

のJava:

public interface ISubject { 
    public void a() 
    //... 
} 

public class CSubject implements ISubject { 
    public void a() { /*...*/ } 
    public void b() { /*...*/ } 
    //... 
} 

public abstract class AbstractTest { 
    ISubject subject; 
    //... 

    public CSubject generateParticularSubject() { 
    return new CSubject(); 
    } 
} 

スカラ:

object Test extends AbstractTest { 

    override val subject: CSubject = generateParticularSubject() /*1*/ 

    subject.b() /*2*/ 
} 

問題があります。if '1'と書かれた行は上のコードのとおりですが、コンパイラはoverriding variable subject in class AbstractTest of type ISubject; value subject has incompatible typeという文句を言います。 1行目の型名annotation : CSubjectとキーワードoverride valを削除した場合、そのエラーは消えますが、もう1行目は「2」に表示されます:value b is not a member of ISubject

私はこれらのエラーが何を言っているのか、そしてコンパイラがこれらの問題をどのように考えているのかを理解しています。私が理解できないことは、Javaの場合と同じように動作を取得する方法です。クラスのインターフェイスメンバーを実装する場合、インターフェイスを実装する任意の種類のクラスで初期化することができます。 Scalaでこれを行う方法は何ですか?

更新日: Scalaでこのような構造を実現することは不可能なのは本当ですか?私がそれをしたいのは、AbstractTestには、サブジェクトのISubjectを扱うメソッドと、subjectをオーバーライドし、それをより狭いクラスインスタンスとして定義する子クラスがあり、そのクラスに固有のメソッドを実装する必要があるからです。それと同時に、私はAbstractTestがすべてsubjectについて扱い続けたいと思っており、それはそのインターフェイスISubjectを通して扱われている間に処理することができます。

答えて

3

Javaフィールドsubjectは可変であるため、valを使用してScalaでオーバーライドすることはできません。また、割り当て可能であるため、それを共変に変化させることは安全ではない。

subjectを抽象メソッドにすることでコードを修正できます。これはScalaコードでやっているように、valと共存するようにオーバーライドすることができます。あなたが求める何

abstract class AbstractTest { 
    public abstract ISubject subject(); 

    //... 

    public CSubject generateParticularSubject() { 
    return new CSubject(); 
    } 
} 
3

Testオブジェクトで達成しようとしていることは明確ではありません。あなたは、単にCSubjectのインスタンスとしてgenerateParticularSubject()方法の結果で作業する必要がある場合は、単に変数に別の名前を使用し、すなわち

object Test extends AbstractTest { 
    subj = generateParticularSubject() 
    subj.b() 
} 

私は理解していない何を、動作は同じ取得する方法ですJavaのように、クラスのインタフェースメンバを実装する場合、そのインタフェースを実装するあらゆる種類のクラスで初期化することができます。 「共変戻り値の型」と呼ばれ、実際に(サブクラスでオーバーライドメソッドが狭いタイプを返すことが許可されていることによって)バージョン5以降、Javaでサポートされているあなたがここに言及されている

。しかし、あなたがScalaのコードでしようとしていることは、共変な戻り値の型には何もありません。代わりに、基本クラスのメンバフィールドをオーバーライドしようとしています。このフィールドは、基本クラスにISubject型を持つと宣言されています。あなたが書くことができる理由は次のとおりです。

object Test extends AbstractTest { 
    subject = generateParticularSubject() 
    // ... 
} 

をだけ、その後ISubjectで定義されたメソッドを呼び出すことができます(それは関係なく、generateParticularSubjectによって返されたタイプの、対象の静的な型であると())

+0

あなたの質問に答えるために、私が達成しようとしているのは、 'Subject'のコア処理を' AbstractTest'クラスに入れることです。しかし、そのクラスの子は、それをより狭いクラスのインスタンスに初期化し、その特定の子クラスに適した、より多くのメソッドを定義する必要があります。同時に、AbstarctTestクラスで定義されているコアメソッドは、より広いISオブジェクトとして 'subject 'を扱うという使命を果たすことができるはずです。 – noncom

+1

私が理解する限り、Java変数では無効にならず、むしろ隠されてしまいます。 – noncom

+0

AbstractTestクラスは、generateParticularSubject()メソッドの宣言から続くCSubject型を認識しています。なぜ、 'AbstractTest.subject'をISubjectではなくCSubjectとして宣言してください。第二に、あなたが正しく言うように、Javaのメンバーフィールドはオーバーライドされたものより薄暗くなります。もしあなたがそのルートに行きたいなら、 'AbstractTest.subject'は実際に私的な可視性で宣言され、' Test'は独自の 'private val subject '狭いタイプの。 – elk

2

私はあなたが持っていると思います2つのオプション。

シンプル1:

object Test extends AbstractTest { 

    val csubject: CSubject = generateParticularSubject() 
    override val subject = csubject 

    csubject.b() 
} 

あなたはCSubjectのインスタンスとして主題アクセスするさまざまな場所持っている場合は特に、1よりよい:

がAbstractTestに拡張型パラメータTを与えるをISubject、タイプTのsubjectを作成し、TestでそのパラメータをCSubjectにバインドします。

1

は、いずれかのScala または Javaでは不可能です。 PythonやRubyは、もちろんそれをやらせてくれるだろうし、それらは間違っているだろう(しかし、あなたは何をしているのか再度確認しない)。

問題は、あなたがやりたいことができ想定し、このです:

class DSubject extends ISubject 
Test.subject = new DSubject 

TestAbstractTestを実装し、AbstractTestは公共の場を持っているので、あなたは、その割り当てを禁止することはできません。割り当てを無効にするとAbstractTestの契約に違反します。

Testオブジェクトでは、subjectにはDSubjectが含まれているため、CSubjectメンバーへのアクセスにはエラーが発生します。

継承の代わりに集約やプロキシクラスなどの何かを試してください。

関連する問題