안드로이드/이론관련

Annotation(어노테이션)?

닉네임못짓는사람 2021. 8. 18. 23:06
반응형

Annotation은 사전적으로 주석이라는 의미를 가지고 있다.

안드로이드 개발 중 @Deprected, @Override @Throws 등을 볼 수 있는데,

컴파일러에게 정보를 제공하거나, 실행 시 특정 코드를 자동적으로 생성해주도록 하는 역할을 하고 있다.

 

Annotation은 기본적으로 Kotlin/Android에 내장되어있는 built in annotation,

Annotation에 대한 정보를 나타내는 meta annotation, 개발자가 직접 만드는 cumstom annotation이 있다.

 

이번 글에선 Kotlin에서 사용하는 annotation을 몇 가지 알아보자.

1. @JvmName

2. @JvmStatic

3. @JvmField

4. @Throws

5. @JvmOverloads


@JvmName

@JvmName은 코틀린을 Byte코드로 변환할 때 JVM 시그니쳐를 변경하기 위해 사용한다.

무슨 뜻인지는 코드를 통해서 확인해보도록 하자.

Kotlin에서 함수의 Signature에 따라 서로 다른 함수인지 구분할 수 있다.

Signature란 간단하게 함수명+파라미터인데, 위의 exFun함수의 경우 Signature는 exFun(List)라고 할 수 있다.

 

여기서 보통 우리가 함수에서 List를 사용하면 Generic을 사용하게 되는데, 함수의 Signature는 이 Generic을 고려하지 않는다.

때문에 위의 두 exFun함수는 서로 같은 Signature를 가지기 때문에 아래와 같이 에러가 발생하게 된다.

이때 @JvmName을 사용하면 함수의 Signature를 변경해서 두 함수의 중복을 없앨 수 있다.

이렇게 @JvmName으로 Signautre를 바꿔주면 함수명을 따로 구분 짓지 않고도

파라미터로 들어가는 List의 Generic에 따라 서로 다른 함수를 호출할 수 있게 된다.


@JvmStatic

@JvmStatic은 함수와 프로퍼티에 static하게 접근할 수 있도록 추가적인 메서드 또는 getter / setter를 생성한다.

코드로 사용법을 확인해보자.

예를 들어 위와 같은 object가 있다고 했을 때, Kotlin에선 이에 직접적으로 접근할 수 있다.

하지만 이 Kotlin 파일을 Java에서 사용하려고 하면 Error가 발생한다.

public static void main(String[] args){
    exam.printList(Arrays.asList("1", "2", "3");	//Error
    System.out.println(exam.a);				//Error
}

Java에서 위 Kotlin코드를 사용하려면, 아래와 같이 작성해주어야 한다.

public static void main(String[] args){
    exam.INSTANCE.printList(Arrays.asList("1", "2", "3");	//Error
    System.out.println(exam.INSTANCE.a);			//Error
}

이러한 문제를 해결하기 위해 @JvmStatic을 사용하는데,

위와 같이 @JvmStatic을 object내에서 선언해주면 Java코드에서 직접적으로 접근이 가능하게 된다.

즉, @JvmStatic은 Kotlin의 object를 Java의 static처럼 선언하여 Kotlin과 Java의 호환을 위해서 사용한다고 볼 수 있다.


@JvmField

@JvmField는 get/set을 생성하지 말라는 의미이다.

Kotlin에서 property를 사용할 때는 기본적으로 getter / setter를 통해서 노출한다.

위 코드를 @JvmField없이 Java코드로 변환하면 아래와 같이 될 것이다.

public static class Exam{
    private int a;
    public final int getA(){
	return this.a;
    }
    public final void setA(int var1){
    	this.a = var1;
    }
}

이때 @JvmField를 사용하면, getter / setter없이 노출하게 된다.


@Throws

@Throws는 매우 자주 보이는 Annotation중 하나인데, 다들 알다시피 예외를 떠넘기는 역할을 한다.

Kotlin또는 Java에서 예외처리를 할 때에는 try~catch를 사용해서 처리를 할 수 있는데,

이 외에도 Java에선 throws를 사용해 자신을 호출한 함수에게 예외를 떠넘길 수가 있다.

@Throws는 Kotlin에서 Java의 throws와 같은 역할을 한다.

위의 코드에선 크기가 3인 list에서 5번째 인덱스에 접근하려고 하기 때문에

ArrayIndexOutOfBoundsException이 발생하게 된다.

@Throws를 사용해서 위 Exception을 자신을 호출한 main함수로 떠넘길 수 있게 된다.


@JvmOverloads

@JvmOverloads는 Kotlin함수의 OverLoading메소드들을 생성해주는 Annotation이다.

코드를 보고 어떻게 사용하는지 확인해보도록 하자.

위 코드를 보면 exam함수에서 b와 c에 default값을 적용한 것을 볼 수 있다.

default는 함수 호출 시 argument를 따로 지정하지 않았을 때 기본적으로 parameter에 들어가는 값을 말한다.

 

코드에서는 b와 c에 0이라는 값이 default로 들어가도록 되어있다.

사실 Kotlin만 사용한다면 따로 문제는 없지만, Java와 같이 사용할 경우 문제가 발생하게 된다.

Java에는 default값 개념이 없기 때문에 위와 같은 형태가 불가능하고, 기본적으로 모든 argument를 입력해주어야 한다.

 

때문에 위의 Kotlin코드를 Java에서 가져다 쓴다고 하면 당연히 Error가 발생할 수밖에 없다.

이때 @JvmOverloads를 사용하면 Kotlin코드를 Java에서 사용할 때 default값을 지정하는 함수들을 자동적으로 생성해준다.

두 코드를 Java코드로 변환시켜서 비교해보면 아래와 같은 결과가 나온다

1. @JvmOverloads사용안함.

argument 3개를 입력해야 하는 exam함수 하나만 생성됨

2. @JvmOverloads사용.

b와 c에 default값(0)이 들어가는 함수들이 추가로 생성

반응형