web-dev-qa-db-ja.com

コンパニオンオブジェクトで@JvmStaticを使用する理由とタイミング

@JvmStaticの使用の有無の違いと、どちらを使用すべきかを理解しようとしています。

したがって、KotlinとJavaを使用すると、次のことができます。

TestKotlin.kt

class TestKotlin {
    companion object {
        val someString = "hello world"
    }
}

次のように、Javaによって呼び出されます。

TestJava.Java

public class TestJava {
    String kotlinStaticString = TestKotlin.Companion.getSomeString();
}

しかし、その後、このオプション2があります:

TestKotlin.kt v2

class TestKotlin {
    companion object {
        @JvmStatic  // <-- notice the @JvmStatic annotation
        val someString = "hello world"
    }
}

次に、次のようにJavaから呼び出します。

TestJava.Java v2

public class TestJava {
    String kotlinStaticString = TestKotlin.getSomeString();
}

だから私の質問は:

  • これら2つのケースは、動作またはメモリ割り当ての点で異なっていますか?
  • どちらを使用するかについての好みはありますか?
  • 両方ともJava staticのような擬似静的シングルトンオブジェクトを作成しますか?

ありがとう!

28
TooManyEduardos

@JvmStaticアノテーションの動作については、 ドキュメント で詳しく説明されています。ドキュメントを読むとき、すべての重要な情報が提供され、ドキュメントに記載されていない動作の違いは存在しないと想定する必要があります。

この場合、ドキュメントには次のように記載されています。

この注釈を使用すると、コンパイラはオブジェクトの包含クラスの静的メソッドとオブジェクト自体のインスタンスメソッドの両方を生成します。

つまり、注釈の効果は、コンパイラーに追加のメソッドを生成するように指示することです

ドキュメントには、動作またはメモリ割り当てに違いがあると記載されていますか?ありません。したがって、何もないと仮定しても安全です。

どちらを使用するかについての好みはありますか?通常、APIは1つの場所で宣言され、複数の場所で使用されます。 Javaからメソッドを呼び出す場合は、@JvmStaticアノテーションを1か所に追加すると複数の@JvmStatic参照を省略することができるため、.Companionとして宣言する必要があります。 。

Java staticのように、両方とも擬似静的シングルトンオブジェクトを作成しますか?Java staticは「擬似静的シングルトンオブジェクト」。Javaクラスで静的メソッドを宣言し、このメソッドを呼び出した場合、オブジェクトは作成されません。

34
yole

関数を「コンパニオンオブジェクト」に配置します。

Javaこのようなコード:

_class DemoClass {
  public static int myMethod() { return 1; }
}
_

となります

_class DemoClass {
  companion object {
     fun myMethod() : Int = 1
  }
}
_

その後、Kotlinコード内から次のように使用できます。

_DemoClass.myMethod();
_

ただし、Javaコード内では、次のように呼び出す必要があります。

_DemoClass.Companion.myMethod();
_

(これはKotlin内でも動作します。)

Companionビットを指定する必要がない場合は、_@JvmStatic_注釈を追加するか、コンパニオンクラスに名前を付けることができます。

docs から:

コンパニオンオブジェクト

クラス内のオブジェクト宣言は、コンパニオンキーワードでマークできます。

_class MyClass {
   companion object Factory {
       fun create(): MyClass = MyClass()
   }
}
_

コンパニオンオブジェクトのメンバーは、単にクラス名を修飾子として使用して呼び出すことができます。

_val instance = MyClass.create()
_

...

ただし、JVMでは、_@JvmStatic_注釈を使用すると、実際の静的メソッドおよびフィールドとして生成されるコンパニオンオブジェクトのメンバーを持つことができます。詳細については、Java interoperabilityセクションを参照してください。

_@JvmStatic_アノテーションの追加は次のようになります

_class DemoClass {
  companion object {
    @JvmStatic
    fun myMethod() : Int = 1;
  }
}
_

そして、aは、実際のJava静的関数として、Javaとkotlinの両方からDemoClass.myMethod()としてアクセス可能)として存在します。

Companionの名前が嫌いな場合は、コンパニオンオブジェクトの明示的な名前を次のように指定することもできます。

_class DemoClass {
  companion object Blah {
    fun myMethod() : Int = 1;
  }
}
_

同じ方法でKotlinから呼び出すことができますが、Java like DemoClass.Blah.myMethod()(Kotlinでも動作します)から)。

2
Maddy

Kotlinでは、companionオブジェクトを使用して静的動作を模倣できます。呼び出しはJavaの静的呼び出しのように見えますが、“Companion“はifの一部ではありません。 Java=)で使用する場合、@JvmStaticが適用されない限り、companionオブジェクトに名前を付ける必要があります。

TestKotlin.getSomeString() //this should be preferred whenever possible

docs に記載されています:

コンパニオンオブジェクト

クラス内のオブジェクト宣言は、コンパニオンキーワードでマークできます。

class MyClass {
   companion object Factory {
       fun create(): MyClass = MyClass()
   }
}

コンパニオンオブジェクトのメンバーは、単にクラス名を修飾子として使用して呼び出すことができます。

val instance = MyClass.create()

...

ただし、@JvmStatic注釈を使用する場合、JVMでは、実際の静的メソッドおよびフィールドとして生成されたコンパニオンオブジェクトのメンバーを持つことができます。詳細については、Java interoperabilityセクションを参照してください。

前述のようにadditionalメソッドが生成されることに注意してください here

この注釈を使用すると、コンパイラはオブジェクトの包含クラスの静的メソッドとオブジェクト自体のインスタンスメソッドの両方を生成します。

exampleを見てみましょう:

次のクラス

class Outer {
    companion object {
        fun callMe() = ""
    }
}

バイトコードレベルでは次のようになります。ここではJava code:

@Metadata(...)
public final class Outer {
   public static final Outer.Companion Companion = new Outer.Companion((DefaultConstructorMarker)null);

   @Metadata(...)
   public static final class Companion {
      @NotNull
      public final String callMe() {
         return "";
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

ただし、@JvmStaticcallMeメソッドに適用されている場合、バイトコードは次のように変更されます。

@Metadata(...)
public final class Outer {
   public static final Outer.Companion Companion = new Outer.Companion((DefaultConstructorMarker)null);

   @JvmStatic
   @NotNull
   public static final String callMe() {
      return Companion.callMe();
   }

   @Metadata(...)
   public static final class Companion {
      @JvmStatic
      @NotNull
      public final String callMe() {
         return "";
      }

      private Companion() {
      }

      // $FF: synthetic method
      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

callMeの一部が生成されると、静的なOuter関数が正しく文書化されます:

@JvmStatic
@NotNull
public static final String callMe() {        
    return Companion.callMe();
}
1
s1m0nw1