2017-03-26 8 views
4

メソッドにメソッドを追加すると、メタクラスはそれをインタフェース実装のすべてのインスタンスに追加します。すべての実装クラスにメソッドを追加すると、毎回変更が発生します。インタフェースメタクラスへのメソッドの追加は、一度しか動作しません

メソッドの再割り当ての間にmetaClassをクリーニングしても、何も変更されていないようです。ここで

は、実行可能な例である:

interface X {} 
class A implements X {} 
class B implements X {} 

X.metaClass.test = { println "v1" } 
new A().test() 
new B().test() 

X.metaClass.test = { println "v2" } 
new A().test() 
new B().test() 

A.metaClass.test = { println "v3" } 
B.metaClass.test = { println "v3" } 

new A().test() 
new B().test() 

A.metaClass.test = { println "v4" } 
B.metaClass.test = { println "v4" } 

new A().test() 
new B().test() 

と結果は次のとおりです。

v1 
v1 
v1 
v1 
v3 
v3 
v4 
v4 

これは意図された動作ですか?もしそうなら、なぜですか?それともバグですか?

+0

あなたは 'v2'を期待していますか?インタフェースでは、どのように同じメソッドを宣言できますか?一度右か? – Rao

+0

出力が期待されます。あなたの期待は何ですか? – dsharew

+1

そうです、 'X'インターフェースの' test'メソッドをオーバーライドすると、オーバーライドされた振る舞い、つまり "v2"文字列を表示するために呼び出されることが予想されます。 申し訳ありませんが、私はあなたの修辞的な質問の明白さを本当に理解していません。私が 'metaclass.someMethod'のようにsthを実行すると、私は実際に同じメソッドを2回宣言していないと思いますが、前の宣言をオーバーライドします。これを他の方法でやる方法はありますか? –

答えて

2

おっと、これは実際には長年の未解決のバグ(GROOVY-3493)である可能性があります。メソッド内でメソッドが宣言されると、それをmetaClassでオーバーライドすることはできないという問題があるようです。この制限はクラスには適用されません。

私が推測するのは、metaClassを使ってメソッドを宣言するのは初めてです。以前は存在しなかったので、適切に初期化されています。しかし、インタフェースmetaClassメソッドのそれ以降の更新は、すでに存在するため、機能しません。 metaClassクラスの変更は、このバグがそれらには当てはまらないので動作します。

チケットに記載されている回避策は、見つかった回避策と似ています。つまり、インターフェースとクラスの両方でmetaClassを更新してください:

​interface X {} 
class A implements X {} 
class B implements X {} 

X.metaClass.test = { println "v1" } 

new A().test() 
new B().test() 

X.metaClass.test = { println "v2" } 
A.metaClass.test = { println "v2" } 

new A().test() // Will print "v2" 
new B().test()​ // Will print "v1" still 
+1

うわー、バグを見つけてくれてありがとう、私もそれを探したが失敗した。長期間の言語機能のバグは、まともな開発者が期待するものではありませんので、それが実際に実際に起こっていることを知ることは本当に良いことです。 そして... 8年、素敵!これは、#ProvidedGate https://issues.gradle.org/browse/GRADLE-784よりもさらに味付けされており、解決されていません。 私は賞金をほんの数日間残しておきます。多分もっと注目を集めるでしょう。 –

関連する問題