JAVA - Call by Value, Call by Reference
Java에서 인수로 매개 변수를 전달하는 방식은 크게 두 가지가 있는데, 기본 데이터형은 모두 Call by Value로 처리되고, 클래스의 객체는 Call by Reference로 처리된다.
Call by Value
Java에서 인수로 기본 데이터형을 사용하면 모두 Call by Value가 된다. Call by Value는 주어진 값을 복사하여 처리하는 방식이다. 따라서 메소드 내의 처리 결과는 메소드 밖의 변수에는 영향을 미치지 않는다.
public class CallByValue { public static void swap(int x, int y) { int temp = x; x = y; y = temp; } public static void main(String[] args) { int a = 10; int b = 20; System.out.println("swap() 메소드 호출 <전>: a="+a+", b="+b); swap(a,b); System.out.println("swap() 메소드 호출 <후>: a="+a+", b="+b); } }
# 결과
swap() 메소드 호출 <전>: a=10, b=20
swap() 메소드 호출 <후>: a=10, b=20
swap() 메소드 호출 <전>: a=10, b=20
swap() 메소드 호출 <후>: a=10, b=20
a와 b의 값이 바뀌도록 하고 싶다면, a와 b를 전역 변수로 선언하거나, Call by Reference를 사용하면 된다.
Call by Reference
Call by Reference는 매개 변수의 원래 주소에 값을 저장하는 방식이다. Java에서는 클래스 객체를 인수로 전달한 경우에만 Call by Reference로 처리한다.
class Number { public int a; public int b; } public class CallByReference { public static void swap(Number z) { int temp = z.a; z.a = z.b; z.b = temp; } public static void main(String[] args) { Number n = new Number(); n.a = 10; n.b = 20; System.out.println("swap() 메소드 호출 <전>: a="+n.a+", b="+n.b); swap(n); System.out.println("swap() 메소드 호출 <후>: a="+n.a+", b="+n.b); } }
# 결과
swap() 메소드 호출 <전>: a=10, b=20
swap() 메소드 호출 <후>: a=20, b=10
swap() 메소드 호출 <전>: a=10, b=20
swap() 메소드 호출 <후>: a=20, b=10
number 클래스의 객체를 생성하여 값을 전달하게 되면 객체가 저장한 값이 주소값이기때문에 swap( ) 메소드에서 객체에 저장한 결과가 main( ) 메소드로 돌려지게 된다.
main( ) 메소드에서 Number 클래스의 객체인 n을 만들어 인수로 전달하기 때문에 swap( ) 메소드 내에서 Number 클래스 내의 x, y의 값을 바꾼 결과가 main( ) 메소드에 영향을 미치게 된다. 이렇게 다른 메소드에서 현재의 메소드 내의 변수 값을 바꾸는 현상을 '사이드 이펙트(side effect)'라고 한다.
'사이드 이펙트'는 메소드 간의 값 전달을 쉽게 하기 때문에 편리하지만, 실수로 프로그래머가 모르는 사이에 값이 바뀌면 심각한 문제를 일으킬 수 있기 때문에 위험하다고 알려져 있다. 그래서 Java는 모든 기본 데이터형은 Call by Value로 값을 주고받아 '사이드 이펙트'가 일어나지 않도록 했고, Call by Reference가 필요한 경우는 명시적으로 클래스 객체를 주고받도록 정해둔 것이다.