kotlin Cloneableの奇妙な行為
2895 ワード
kotlin Cloneableの奇妙な行為
kotlinのCloneableを使っていると、変な表現をしていることに気づきました.クラスが直接Cloneableを継承している場合、その表現は正常でjavaの使用とあまり差がありません.以下のようにします.
この部分のコードは正常に動作しますが、インタフェースFooもCloneableを継承している場合、結果はおかしくなります.コードは次のとおりです.
奇妙なことに、jclasslibを使用して生成されたclassファイルを分析し、興味深い状況を発見しました. Barが直接Cloneableを継承する場合、Barのcloneメソッドは、 である. FooがCloneableを継承した場合、Barのcloneメソッドは:
問題が見つかりました.FooインタフェースにはCloneableが継承されていますが、BarがFooインタフェースを実装すると、kotlinコンパイル後のclassファイルに
この問題はjetbrainsのkotlinコミュニティに報告されています.優先度はMajorです.KT-241993を参照してください.
effiective javaによると、javaのCloneableは奇妙なインタフェースであり、通常のインタフェースの動作とは異なり、言語メカニズム自体を超える約束を使用して、オブジェクトの呼び出しclone()時の動作を示す.
一般的にはclone()の使用は避け,類似の機能を実現するためにコピー構造関数を用いることが考えられる.
kotlinのCloneableを使っていると、変な表現をしていることに気づきました.クラスが直接Cloneableを継承している場合、その表現は正常でjavaの使用とあまり差がありません.以下のようにします.
package demo
interface Foo {
fun createClone(): Foo
fun doSomething()
}
class Bar: Foo, Cloneable {
override fun createClone(): Bar {
return this.clone() as Bar
}
override fun doSomething() {
println("Hello, world!")
}
}
fun main(args:Array) {
val bar = Bar()
bar.doSomething()
val barCloned = bar.createClone()
barCloned.doSomething()
}
この部分のコードは正常に動作しますが、インタフェースFooもCloneableを継承している場合、結果はおかしくなります.コードは次のとおりです.
package demo
interface Foo: Cloneable {
fun createClone(): Foo
fun doSomething()
}
class Bar: Foo, Cloneable {
override fun createClone(): Bar {
return this.clone() as Bar
}
override fun doSomething() {
println("Hello, world!")
}
}
fun main(args:Array) {
val bar = Bar()
bar.doSomething()
val barCloned = bar.createClone()
barCloned.doSomething()
}
bar.createClone()
が呼び出されると、例外が発生します.Exception in thread "main" java.lang.NoClassDefFoundError: java/lang/Cloneable$DefaultImpls
at demo.Foo$DefaultImpls.clone(demo.kt)
at demo.Bar.clone(demo.kt:8)
at demo.Bar.createClone(demo.kt:10)
at demo.DemoKt.main(demo.kt:22)
Caused by: java.lang.ClassNotFoundException: java.lang.Cloneable$DefaultImpls
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 4 more
奇妙なことに、jclasslibを使用して生成されたclassファイルを分析し、興味深い状況を発見しました.
0 aload_0
1 invokespecial #47
4 areturn
このときjava Objectを直接呼び出すcloneメソッド 0 aload_0
1 invokestatic #51
4 areturn
ええ、ここで呼び出されたのはFooインタフェースデフォルト実装クラスです.java 8のインタフェースデフォルト実装です.故障もないようですが、Foo$DefaultImpls.clone
0 aload_0
1 checkcast #9
4 invokestatic #14
7 areturn
を見てみると少し間違っているようです.Cloneableは古いインタフェースで、デフォルト実装はありません.jclasslibもCloneable$DefaultImpls
クラスを見つけられなかった.問題が見つかりました.FooインタフェースにはCloneableが継承されていますが、BarがFooインタフェースを実装すると、kotlinコンパイル後のclassファイルに
Cloneable$DefaultImpls
が呼び出され、kotlinはインタフェースのデフォルト実装を処理する上で問題があります.この問題はjetbrainsのkotlinコミュニティに報告されています.優先度はMajorです.KT-241993を参照してください.
effiective javaによると、javaのCloneableは奇妙なインタフェースであり、通常のインタフェースの動作とは異なり、言語メカニズム自体を超える約束を使用して、オブジェクトの呼び出しclone()時の動作を示す.
一般的にはclone()の使用は避け,類似の機能を実現するためにコピー構造関数を用いることが考えられる.