[JAVA] 기본형과 참조형 알아보기
기본형과 참조형
김영한의 실전 자바 기본편을 보며 정리해보는 자바의 기본형과 참조형
자바의 변수 데이터 타입은 크게 사용하는 값을 변수에 직접 넣을 수 있는 기본형, 객체가 저장된 메모리의 위치를 가리키는 참조값을 넣을 수 있는 참조형으로 분류할 수 있다. 자바에서 참조형을 제대로 이해하는 것은 C언어의 포인터를 이해하는 것 만큼 중요하다! 오늘은 이 기본형과 참조형에 대해서 알아보자.
Call By Value 방식
💡 중요: 자바는 Call By Value 방식을 사용한다!
기본형과 참조형에 대해 설명하기 전에, 간단하게 Call By Value 방식을 알아두고 가야 한다. 함수가 인수를 전달할 때 사용되는 방식은 Call By Value 방식과 Call By Reference 방식으로 나뉜다.
Call By Value는 함수가 인수로 전달받은 값을 복사하여 처리하는 방식이다. 변수가 가진 값을 복사하여 전달하므로 함수 내에서 값을 변경해도 원본 값은 변경되지 않는 불변성을 보장한다.
더 자세한 내용은 다음에 다뤄보기로 하고, 지금은 일단 “자바는 항상 변수의 값을 복사해서 대입한다“에 초점을 두자.
기본형
변수에 사용할 값을 직접 넣을 수 있는 데이터 타입
int
, boolean
, double
, boolean
과 같이 소문자로 되어 있고, 변수에 사용할 값을 직접 넣을 수 있는 데이터 타입을 기본형이라고 한다.
int
형 변수 b
에 a
를 대입하는 코드를 살펴보자.
1
2
int a = 10;
int b = a;
위와 같은 경우를 그림으로 그려보면 다음과 같다.
변수 b
에 a
를 대입하는 경우, a
에 저장된 값 10
을 복사해 b
에 저장하게 된다.
실제적으로 변수 안에 존재하는 값만 복사한다는 것이 중요한 포인트다!
따라서 이후에 a
나 b
를 변경하더라도 각각의 변수에 영향을 끼치지 않는다.
1
2
a = 20;
b = 30;
또, 해당 값은 실제 값이기 때문에 별도의 조작 없이 바로 사용할 수 있다.
1
2
a = b + 10; // 30 + 10
b = a + 10; // 20 + 10
참조형
데이터에 접근하기 위한 참조(주소)를 저장하는 데이터 타입
Dog dog
, int[] values
와 같이 객체나 배열은 데이터에 접근하기 위한 주소를 저장하고 있다. 이런 참조형 변수를 통해 뭔가 하려면 참조값을 통해 해당 위치로 이동해야 한다.
동작 방식을 살펴보기 위해 Data
라는 클래스를 만들어 보자.
1
2
3
public class Data {
int value;
}
멤버 변수로 int value
를 가지는 Data
클래스를 생성했다. 이제 이 클래스를 이용해서 인스턴스를 만들어 주자.
1
2
3
4
5
public static void main(String[] args) {
Data dataA = new Data();
dataA.value = 10;
Data dataB = dataA; // 참조값만 B에 들어간 것
}
dataA
변수는 새로 만들어진 Data
인스턴스의 참조값을 저장하고 있다.
따라서 dataB
에 dataA
를 대입한다는 것은 dataA
가 가지고 있는 참조값(Data
인스턴스의 주소)을 복사해서 저장한다는 뜻이다.
값을 복사해서 저장한다는 것은 기본형과 비슷하지만, 연산과 대입 시에 차이점이 드러나게 된다.
1
2
3
4
// dataA 변경
dataA.value = 20;
// dataB 변경
dataB.value = 30;
참조형 변수의 경우 주소값을 가지고 있기 때문에 기본형처럼 +, -
등의 연산이 불가능하다.
대신 .
키워드를 사용해 해당 참조값에 접근할 수 있다.
dataA.value = 20
은 dataA
가 가지고 있는 참조값 x001
의 value
에 20
을 대입한다는 뜻이다. 따라서 위 그림과 같은 상태가 된다.
dataA
를 대입했던 dataB
는 어떨까?
dataB
도 Data
인스턴스의 주소값인 x001
을 dataA
로부터 복사해 가지고 있으므로 x001
의 value
에 30
을 대입한다는 뜻이 된다. 마찬가지로 Data
인스턴스의 value
값이 30
으로 변경된다.
기본형과 참조형의 메서드 호출
기본형의 메서드 호출
1
2
3
4
5
6
7
8
9
public static void main(String[] args) {
int a = 10;
changePrimitive(a);
System.out.println(a); // 10
}
static void changePrimitive(int x) {
x = 20;
}
변수 a
에 10
이 저장되어 있고 changePrimitive
함수를 호출하면서 a
의 값을 전달하게 된다. 전달된 값은 변수 x
에 복사되어 저장된다.
10
이 저장된 변수 x
에 20
을 대입한다.
x
는 지역변수로 changePrimitive
함수가 종료되면 사라지게 된다.
a
는 단순히 값을 복사해서 전달했으므로 값에 변동이 없다. 따라서 10
을 그대로 출력하게 된다.
참조형의 메서드 호출
1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
Data dataA = new Data();
dataA.value = 10;
changeReference(dataA); // dataA의 참조값을 매개변수로 사용
System.out.println(dataA.value); // 20
}
static void changeReference(Data dataX) {
dataX.value = 20;
}
dataA
는 Data
클래스를 통해 생성된 인스턴스의 참조값이 저장되어 있다.
changeReference
함수를 호출하면서 dataA
가 가지고 있는 참조값을 dataX
로 복사해 전달하게 된다.
즉, dataA
가 가리키고 있는 주소와 dataX
가 가리키고 있는 주소가 같아진다.
changeReference
함수 내에서 dataX.value = 20
은 해당 참조값의 value
를 20
으로 대입하라는 말과 같다. 따라서 위 그림과 같이 value
값을 변경하게 된다.
dataA
도 같은 주소를 참조하고 있으므로 20
을 출력한다.
이런 특성을 활용하면 객체의 참조 값을 전달하거나 반환해 다음과 같이 편리하게 객체의 필드 값을 설정해줄 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static void main(String[] args) {
Dog dog1 = new Dog();
initStudent(dog1, "웰시 코기", 1, 10);
Dog dog2 = setDog("말티즈", 7, 8);
}
static void initDog(Dog dog, String name, int age, int weight) {
dog.name = name;
dog.age = age;
dog.weight = weight;
}
static Dog setDog(String name, int age, int weight) {
Dog dog = new Dog();
dog.name = name;
dog.age = age;
dog.weight = weight;
return dog;
}
정리
- 기본형은 똑같은 건물 두 채를 세우는 거라면 참조형은 한 건물에 입구를 두 개 만드는 것이다.
- 자바에서 메서드의 매개변수(파라미터)는 항상 값에 의해 전달되는데, 이 값이 실제 값인지 참조 값인지에 따라 동작이 달라진다.
- 기본형: 메서드로 기본형 데이터를 전달하면 해당 값을 복사해 전달(호출자의 변수 값에 영향X)
- 참조형: 메서드로 참조형 데이터를 전달하면 참조 값을 복사해 전달(호출자의 객체도 변경O)
- 참조형은 실제 인스턴스가 아니라 인스턴스를 가리키는 참조값을 복사해서 전달되는 것이기 때문에 하나의 인스턴스를 여러 곳에서 참조할 수 있다