p264-269
call by value, reference
자바에서는 메소드를 호출할 때 매개변수로 지정한 값을 메소드의 매개변수에 복사해서 넘긴다. 매개변수의 타입이 기본형일 때는 기본형 값이 복사 되겠지만, 참조형이면 인스턴스 주소가 복사된다.
메소드의 매개변수를 기본형으로 선언하면 단순히 저장된 값만 얻지만, 참조형으로 선언 시 값이 저장된 곳의 주소를 알 수 있기에 값을 읽어오는 것은 물론 값을 변경하는 것도 가능하다.
기본형 매개변수 변수의 값을 읽기만 할 수 있다.
참조형 매개변수 변수의 값을 읽고 변경할 수 있다.
원본 10
다음 수로 변경: 1000
변경 후: 10
class Data {
int x;
}
class test {
static void change(int x) // 클래스 변수가 아니라 클래스 전체를 가져와야 함
{
x = 1000;
System.out.println("다음 수로 변경: " + x);
}
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("원본 " + d.x);
change(d.x);
System.out.println("변경 후: " + d.x);
}
}
change 메소드에서 main 메소드로부터 넘겨 받은 d.x의 값을 1000으로 변경했는데도 main 메소드에서는 d.x의 값이 그대로이다.
왜냐하면,
d.x의 값이 변경된 것이 아니라, change 메소드의 매개변수 x의 값이 변경된 것이다. 즉, 원본이 아닌 복사본이 변경된 것이라 원본에 영향을 미치지 못한다. 이처럼 기본형 매개변수는 변수에 저장된 값을 읽을 수만 있을 뿐 변경할 수는 없다.
원본: 10
다음 수로 변경: 1000
변경 후: 1000
class Data
{
int x;
}
class test {
static void change(Data d)
{
d.x = 1000;
System.out.println("다음 수로 변경: " + 1000);
}
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
System.out.println("원본: " + d.x);
change(d);
System.out.println("변경 후: " + d.x);
}
}
change 메소드의 매개변수가 참조형이라서 값이 아니라 값이 저장된 주소를 change 메소드에서 넘겨주었기 때문에 값을 읽어오는 것뿐만 아니라 변경하는 것도 가능하다.
change 메소드의 매개변수를 참조형으로 선언했기 때문에, x의 주소가 매개변수 d에 복사되었다. 이제 main 메소드의 참조변수 d와 change 메소드의 참조변수 d는 같은 객체를 가리키게 된다. 그래서 매개변수 d로 x 값을 읽는 것과 변경하는 게 가능하다.
8
8
int add(int a, int b)
{
return a + b;
}
void add(int a, int b, int[] result)
{
result[0] = a + b; // 매개변수로 넘겨받은 배열에 연산결과 저장
}
public static void main(String[] args) {
test r = new test();
int result = r.add(3, 5);
System.out.println(result);
int[] result2 = {0}; // 배열의 생성하고 result2[0]의 값을 0으로 초기화
r.add(3, 5, result2); // 배열을 add 메소드의 매개변수로 전달
System.out.println(result2[0]);
}
위 예제는 반환 값이 있는 메소드를 반환 값이 없는 메소드로 바꾸는 방법이다. 앞서 배운 참조형 매개변수를 활용하면 반환 값이 없어도 메소드의 실행 결과를 얻을 수 있다.
int add(int a, int b)
{
return a + b;
}
↓
void add(int a, int b, int[] result)
{
result[0] = a+b;
}
메소드는 하나의 값만을 반환할 수 있지만 이 것을 응용하면 여러 개의 값을 반환받는 것과 같은 효과를 얻을 수 있다. 어떻게??
참조형 반환 타입
매개 변수 뿐만 아니라 반환 타입도 참조형이 될 수 있다. 모든 참조형 타입의 값은 '객체의 주소'이므로 그저 정수 값이 반환되는 것일 뿐 특별할 것이 없다.
d.x = 10
d2.x = 10
class Data
{
int x;
}
class test {
static Data copy(Data d)
{
Data tmp = new Data();
tmp.x = d.x;
return tmp;
}
public static void main(String[] args) {
Data d = new Data();
d.x = 10;
Data d2 = copy(d);
System.out.println("d.x = " + d.x);
System.out.println("d2.x = " + d2.x);
}
}
copy 메소드는 새로운 객체를 생성한 다음, 매개변수로 넘겨받은 객체에 저장된 값을 복사해서 반환한다. 반환하는 값이 Data 객체의 주소이므로 반환 타입이 'Data'이다.
static Data copy(Data d)
{
Data tmp = new Data(); // 새로운 객체 tmp 생성
tmp.x = d.x; // d.x의 값을 tmp.x에 복사
return tmp; // 복사한 객체의 주소 반환
}
이 메소드의 반환 타입이 'Data'이므로, 호출 결과를 저장하는 변수의 타입 역시 'Data' 타입의 참조 변수여야 한다.
Data d2 = copy(d); // static Data copy(Data d)
copy 메소드 내에서 생성한 객체를 main 메소드에서 사용하려면, 위와 같이 새로운 객체의 주소를 반환해줘야 한다. 그렇지 않으면 copy 메소드가 종료되면서 새로운 객체의 참조가 사라진다.