Programming/Kotlin

Kotlin/Java의 Primitive type, Reference type

YK Choi 2021. 5. 3. 18:46

Android Programming에서 Kotlin/Java 언어에 대한 기본은 아무리 강조해도 지나치지 않다고 생각한다.

 

Primitive type, Reference type의 혼동으로 놓치기 쉬운 이슈를 방지하는 차원에서 복습해보자.

 

 

Kotlin을 들여다 보기전에 Java에 대해 먼저 짚고 넘어가자.

 

 


Java

 

Java의 자료형에는 크게 Primitive typeReference type이 있다.

primitive type은 소문자로 시작하는 short, int, byte, char, long, float, double 등이 있다.

reference type은 이를 제외한 대분자로 시작하는 String, ArrayList, Class type 등이 있다.

 

Java에서 함수를 호출할 때 

매개변수가 primitive type과 Reference type 인지에 따라 내부 동작이 조금 다르다.

 

우선,

primitive type은 메모리 공간에 변수가 가지는 값을 저장하고

reference type은 객체가 저장되어있는 주소를 저장한다.

 

 

예시 1) call by value를 통해 primitive type의 값을 복사하여 함수를 실행한다.

따라서 callee가 return 되어도 caller의 parameter 데이터는 변하지 않는다.  

 

primitive type 예시

 

예시 2) reference type은 객체를 넘길때 그 객체를 가리키는 새로운 지역변수를 생성하여 그것을 통해 같은 객체를 가리킨다. 따라서 callee는 argument값을 변경하면 caller의 데이터를 변경시킬 수 있다.

 

Reference type 예시

caller 에서 ArrayList에 10과 20을 넣고, callee에서 30을 넣은 뒤,

caller에서 ArrayList를 출력했을 때 callee에서 변경한 값이 적용되었다.

 

 

 

예시 3) Wrapper Class 중 하나인 Integer도 똑같이 실험을 해보자.

Object이므로 Reference type이다.

 

Wrapper class 예시

 

여기선 callee의 변수가 가리키는 값이 변하지는 않았다.

이유는 fun2()에서 받은 객체는 callee의 argument의 복사본이고,

실제 메소드 안에서 변경될 때는 지역변수이기 때문이다.

 

 

위의 ArrayList예시 처럼 caller의 객체 값을 변화(위의 예시에선 add(30) )시키는 것이 아닌,

callee의 지역 변수에서 값을 +100 했기 때문에 caller에는 영향이 없는 것이다.

 

다른 비슷한 예시로 callee에서 전달받은 String을 concat()하는 것은 caller에 변경이 적용되지 않지만, callee에서 전달받은 StringBuilder를 append()하는 것은 caller에 변경이 적용된다.

 

 


Kotlin

 

위의 3가지 실험이 전부 의미있는 이유는 Kotlin에서는 primitive type이 없기 때문이다.

 

Kotlin을 Java로 변환했을 때 Kotlin의 Int는 Java의 int로 변환되며 Nullable인 Int?Integer로 변환된다.

하지만 예시 3에서 본 것처럼 Integer는 callee의 변화가 caller에 영향을 주지 않는 것을 확인하였다.

 

아래 예제들은 Kotlin에서 위의 예제들을 적용해본 코드이다.

 

Kotlin의 ArrayList 예시
Int? type의 예시

 


결론

Java와 Kotlin에는 Call by Value만이 존재한다.

위의 ArrayList 예시처럼 call by reference같은 효과는 복사된 변수가 같은 객체를 가리켰기 때문이다.

 

Java의 특징은 객체를 메소드로 넘길 때 객체를 참조하는 지역변수의 실제 주소를 넘기는 것이 아니라, 그 지역변수가 가리키고 있는 힙 영역의 객체를 가리키는 새로운 지역변수를 생성하여 그것을 통해 같은 객체를 가리키도록 하는 방식이다. Kotlin 또한 마찬가지다.

 

그러나 함수형 프로그래밍 방식에서 위의 ArrayList 예제와 같은 방식은 지양해야한다.

함수형 프로그래밍에서 순수 함수는 side effect를 발생시키지 않아야 하기 때문이다.

위의 예제는 side effect를 발생시키기에 좋은 환경이다.

 

함수 내에서 argument는 냅두고, 이를 이용해서 새로운 변수를 데이터를 만들어 활용하는 방식이 코드가 간결하고 개발 생산성과 유지 보수성, 안정성이 증대된다.

 

 

지금까지 같은 Call by reference 이더라도 다르게 작동되는 원리와 경계해야할 방식에 대해 알아보았다.

 

참고한 사이트

https://hyoje420.tistory.com/6

https://cjlee38.github.io/java/java_wrapper_class