Language/Java

[Java] 자바 Call by value... Call by reference?

KAispread 2022. 5. 14. 13:30
728x90
반응형
메소드를 사용하면서 메소드 바깥에 선언된 변수를 '매개변수'를 통해 넘겨줄 수 있다.
그럼 메소드안에서 이 매개변수로 전달받은 값을 변경해주었을때 메소드 호출 이후에도 변경된 값이 유지될까?
결론부터 말하자면 기본 자료형(int, float 등)은 변경되지 않고
참조 자료형(객체 등)은 변경된다.

 


 

Call By Value, Call By Reference 

메소드에 매개 변수가 호출될 때 '값'을 전달하는지 '주소'를 전달하는지에 따라 아주 큰 차이가 있다.

매개 변수에 을 전달하는 방식을 Call By Value,
주소를 전달하는 방식을 Call By Reference 라고 한다.
(Pass By Value, Pass By Reference라고도 한다.)

Call By Value의 값을 전달하는 방식은 매개 변수로 들어온 값을 메소드내에서 변경해주어도
메소드 바깥에서 값이 변경되지 않고,
Call By Reference의 주소를 전달하는 방식은 해당 변수의 메모리 주소에 직접적으로 접근하기 때문에 메소드내에서 값을 변경해주면 메소드 바깥에서도 변경된 값이 유지된다.

예시를 통해 살펴보자.

 

 

 기본 자료형은 Call By Value 

기본 자료형에는 byte, short, int, long, float, double, char, bool 이 있다. 
이들을 원시 변수(Primitive Value) 라고도 하는데 이 변수들을 메소드의 매개 변수로 넘겨주면
'값'만 메소드에 전달되어 매개 변수에 할당된다.

 

public class ValueRefExample {

  public static void main(String[] args) {
 	ValueRefExample sample = new ValueRefExample(); 
	int num = 3;
	float num2 = 3.2f;
	String name = "MinSu";
		
	System.out.println("Before Call By Value    :: num = "+num+" num2 = "+num2+" name = "+name+" ");
	sample.changeParameters(num, num2, name);
	System.out.println("After Call By Value     :: num = "+num+" num2 = "+num2+" name = "+name+" ");
  }	
	
  public void changeParameters(int number, float number2, String alias) {
	number = 10;
	number2 = 3.245f;
	alias = "JinWoo";
	System.out.println("In Method Call By Value :: num = "+number+" num2 = "+number2+" name = "+alias+" ");
  }
}

 

위의 예시 코드에서 main 함수에 String, int, float 형의 변수 3개를 선언하고,
changeParameters라는 함수에 이들을 매개 변수로 넘겨주었다.

changeParameters 함수에서 매개 변수들에 새로운 값을 할당해주었다.
이 메소드 실행 이후에도 이 세가지 변수 값이 변경되었는지 확인해보았다.
결과를 보자.

 

코드 실행 결과

 

위의 결과처럼 메소드 안에서 값을 변경해주어도 이후에 값이 저장되지 않는 것을 확인할 수 있다.

우선, 매개 변수는 해당 메소드 내에서만 유효하고 메소드 실행이 끝날 경우, 매개 변수도 소멸된다.
changeParameters 함수의 매개 변수로 num 이라는 변수를 넘겨주게 되면, num에 저장되어있는 '3'이라는 값만 메소드에 넘어가게 된다.
즉, 메소드 내에서만 유효한 int number = 3 이라는 변수가 새로 선언된다.

 

값 전달방식 예시

 

int number 이라는 변수는 매개 변수로써 메소드 내에서만 유효하므로,
메소드 바깥에서는 값이 변경되지 않는 것이다.

String은 참조 자료형인데도 메소드 밖에서 값이 변경되지 않았다.
그 이유는 String은 값의 재할당이 불가능한 상수이다.
따라서, String 변수에 새로운 값을 할당해주면 기존의 String 객체을 버리고 새롭게 객체를 생성하는 것과 같다.
(+ 연산으로 문자열을 합쳐주는것도 동일)

alias = "JinWoo"
alias = new String("JinWoo")

마찬가지로, 메소드 내에서 생성된 객체, 변수 등은 메소드 내에서만 유효하므로
메소드 실행이 끝날 경우 소멸하게 되어, 값이 변경되지 않는 것이다.

 

 

 객체는 Call By Reference? 

위의 예시에서는 매개 변수로 값이 전달되어 메소드 호출 이후에 변경된 값이 유지되지 않았다.
하지만, 참조 자료형인 객체를 매개 변수로 전달할 경우 '주소값'이 전달되어 
메소드 호출 이후에도 변경된 값이 유지된다. 

사실, 이 또한 주소를 직접 참조하는 것이 아니라 객체의 '주소값'이 복사되어 매개 변수에 저장되기 때문에 실질적으로 Call By Value로 동작하지만, 객체에 대한 참조(Reference)가 넘어가 메소드 내에서 변경된 값이 유지된다는 점에서는 Call By Reference라고도 볼 수 있다.

class Dog {
  int age;
  String name;
	
  Dog() {
	this.age = 10;
	this.name = "Boogie"; 
  }
	
  public int getAge() {
	return this.age;
  }
  public String getName() {
	return this.name;
  }
}

public class ValueRefExample {

  public static void main(String[] args) {
	ValueRefExample sample = new ValueRefExample(); 
	Dog dog = new Dog();
		
	System.out.println("Before Call By Reference    :: age = "+dog.age+" name = "+dog.name+"");
	sample.changeParameters(dog);
	System.out.println("After Call By Reference     :: age = "+dog.age+" name = "+dog.name+"");
  }

  public void changeParameters(Dog ddg) {
	ddg.age = 3;
	ddg.name = "Hariang";
	System.out.println("In Method Call By Reference :: age = "+ddg.age+" name = "+ddg.name+"");
  }
}

 

Call By Value 예시 코드와 같이 메소드내에서 객체의 인스턴스 변수값을 변경해주었다.
그리고 메소드 호출 이후에도 변경된 값이 유지되는지 확인해보았다.
결과를 보자.

코드 실행 결과

 

코드 실행 결과, 메소드 호출 이후에도 변경된 값이 유지되는 것을 확인할 수 있다.

 

 결론 

자바의 메소드에서 매개 변수가 호출되는 방식에 대해서 알아보았다.
사실 자바는 기본 자료형이든 참조 자료형이든 '값'이 복사되어 전달되기 때문에 Call By Value 방식만이 존재한다.

하지만 클래스 객체와 같은 참조 자료형을 매개 변수로 전달할때는 '주소값'이 전달되어 다른 언어의 Call By Reference방식 처럼 메소드 내에서 변경한 값이 메소드 호출 이후에도 유지되게끔 할 수 있다.

이와 같은 개념은 아주 중요하고, 실제 코딩할때도 항상 염두에 두어야 하므로 개념을 확실하게 짚고 넘어갈 필요가 있다.

 

참고
ㆍ자바의 신 vol.1 (이상민)
ㆍhttps://velog.io/@ahnick/Java-Call-by-Value-Call-by-Reference
728x90
반응형