본문 바로가기
안드로이드/코틀린

JvmStatic 어노테이션

by 나이아카 2023. 3. 16.

 회사에서 작성중인 안드로이드 코드가 거의 대부분 자바로 이루어져 있어 코틀린으로 변환하는 중에 있는데, 코틀린으로 작성할 때 상호작용하는 자바코드를 신경써야 하다보니 이것저것 많이 찾아보게 되는 것 같습니다. 이번에 시간이 남아 사용중인 것들을 하나씩 정리해야겠습니다.


@JvmStatic

이 어노테이션의 경우, java의 static처럼 사용할 수 있도록 도와주는 어노테이션입니다.

 코틀린에서 객체를 선언하지 않고 바로 참조하는 static 형태의 경우 companion object 및 object 키워드를 통해 사용하곤 하는데, 이렇게 사용하는 경우 자바 코드에서는 Class.Companion.method 혹은 Class.INSTANCE.method 형태로 바꿔 사용해야 합니다.

 코틀린에서는 큰 차이를 느끼지 못할 수 있어 괜찮지만, 만약 자바에서 기존에 static하게 사용하고 있었다면 자바 코드의 수정 없이 사용하기 위해서 @JvmStatic 어노테이션을 이용할 수 있습니다. 이 어노테이션을 사용하는 경우와 사용하지 않는 경우의 예를 보며 확인해보겠습니다.

class TestCase {
    companion object {
        var isTest : Boolean = false
        var testCseCount : Int = 0
    }
}

 먼저 위와 같은 코틀린 코드를 자바로 변환하는 경우 어떤식으로 변환되는지 확인해보겠습니다.

public final class TestCase {
   private static boolean isTest;
   private static int testCseCount;
   @NotNull
   public static final Companion Companion = new Companion((DefaultConstructorMarker)null);

   public static final class Companion {
      public final boolean isTest() {
         return TestCase.isTest;
      }

      public final void setTest(boolean var1) {
         TestCase.isTest = var1;
      }

      public final int getTestCseCount() {
         return TestCase.testCseCount;
      }

      public final void setTestCseCount(int var1) {
         TestCase.testCseCount = var1;
      }

      private Companion() {
      }

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

 위 코드에서 특이점은 Companion class가 생성되었고, 그 안에 getter/setter가 존재한다는 것입니다. 이는 자바 코드에서 TestCase.Companion.testCaseCount 형태로 사용해야한다는 것을 의미합니다.

 

class TestCase {
    companion object {
        @JvmStatic var isTest : Boolean = false
        @JvmStatic var testCseCount : Int = 0
    }
}

 위의 코드는 자바로 변경하면 아래와 같습니다.

public final class TestCase {
   private static boolean isTest;
   private static int testCseCount;
   @NotNull
   public static final Companion Companion = new Companion((DefaultConstructorMarker)null);

   public static final boolean isTest() {
      Companion var10000 = Companion;
      return isTest;
   }

   public static final void setTest(boolean var0) {
      Companion var10000 = Companion;
      isTest = var0;
   }

   public static final int getTestCseCount() {
      Companion var10000 = Companion;
      return testCseCount;
   }

   public static final void setTestCseCount(int var0) {
      Companion var10000 = Companion;
      testCseCount = var0;
   }

   public static final class Companion {

      public final boolean isTest() {
         return TestCase.isTest;
      }

      public final void setTest(boolean var1) {
         TestCase.isTest = var1;
      }

      public final int getTestCseCount() {
         return TestCase.testCseCount;
      }

      public final void setTestCseCount(int var1) {
         TestCase.testCseCount = var1;
      }

      private Companion() {
      }

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

 두 코드의 가장 큰 차이점은 Companion 외부에 동일한 코드가 존재한다는 것입니다. 이는, 자바 코드에서 TestCase.isTest 형태로 작업이 가능하다는 것을 의미합니다. 기존에 자바 static을 사용하던 class의 syntax 수정 없이 사용할 수 있게 되었다는 것을 의미합니다.


 거의 대부분 코틀린만 사용해서 안드로이드를 작업할 때에는 사실 코틀린 코드가 어떤식으로 자바로 디컴파일되는지 여부를 공부할 때 이외엔 잘 안찾아보게 되었는데, 자바로 된 코드가 남아 있어 코틀린과 혼용해서 써야 하는 상황이 오니 적극적으로 자바 코드로 어떻게 변형되는지를 찾게 되는 것 같습니다. 이렇게 자바와 코틀린이 어떻게 변형되는지 파악하면서 코딩하는 것도 좋은 경험이 되는 것 같습니다.

'안드로이드 > 코틀린' 카테고리의 다른 글

(Kotlin) Flow - 1  (0) 2023.08.10
AAC Navigation의 특징  (0) 2023.06.02
Kotlin - Object 키워드(with SingleTon)  (1) 2023.02.17
Coroutine 관련 설명 글 링크  (0) 2022.06.30
(Android) square - Retrofit  (0) 2022.05.18

댓글