본문 바로가기

Java&JSP&Spring/Java

[JAVA]자바의 Call by Value / Call by Reference

[JAVA]자바의 Call by Value / Call by Reference

자바의 Call by Value / Call by Reference에 대해서 머릿속에 정리가 안되어있어서

이번에 간단하게 예제를 남겨서 정리를 해 봅니다.

 

제목에 언급된 Call by Value / Call by Reference는 언제 쓰이는 개념인가 하면

메소드(함수)를 호출할때 호출한 함수에 넣은 인자값이 실제값이냐 참조값(주소값)이냐를 구분하는 개념이라고

보면 되겠습니다.

 

해당 개념을 공부하기 전에 먼저 알아두어야 하는 개념이

자바의 메모리 구조인데요

포스팅으로 정리해보려고 했지만 알아보기 쉽게 정리가 된 포스팅이 있어서 링크를 남겨봅니다.

 

아래 포스팅 내용에서 중점적으로 보아야 하는 부분은

Heap영역과 Stack영역의 차이점에 대해서 이해하는게 중요합니다.

 

마로의 Java(자바) 정리 - 8. 자바 메모리 구조

JVM 구조 실행될 클래스 파일을 메모리에 로드 후 초기화 작업 수행 메소드와 클래스변수들을 해당 메모리 영역애 배치 클래스로드가 끝난 후 JVM은 main 메소드를 찾아 지역변수, 객체변수, 참조

hoonmaro.tistory.com

 

Call by Value(Pass by Value)

간단하게 "호출한 메소드에 주소 안에 있는 값을 복사해서 보낸다" 라고 생각하면 됩니다.

자바의 변수에는 모두 각각의 주소가 존재합니다.

변수를 선언하고 값을 세팅하면 메모리에서는 해당 주소안에 값을 세팅합니다.

기본적으로 프리미티브 타입과 String타입이 이에 해당됩니다.

 

예제

public class Student {
	String name;
	int age;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

public static void main(String[] args) {

    Student std = new Student();
    std.name = "Hong";
    std.age = 20;

    System.out.println("====== Call By Value ======");
    CallByValue(std);
}

public static void CallByValue(Student std) {
    System.out.println("Name : " + std.name);
    System.out.println("age : " + std.age);

    ChangeValue(std.name, std.age);

    System.out.println("Changed Name : " + std.name);
    System.out.println("Changed age : " + std.age);
}

    private static void ChangeValue(String name, int age) {
    System.out.println("=== Change Value ===");

    name = "Kim";
    age = 10;
}

결과

====== Call By Value ======
Name : Hong
age : 20
=== Change Value ===
Changed Name : Hong
Changed age : 20

ChangeValue에서 Hong을 Kim으로, age를 20에서 10으로 바꾸려고 했는데

바뀌지가 않았네요.

 

이유는 CallByValue(Student std)메소드에 있는 변수들의 주소와 ChangeValue(String name, int age)에 있는 변수들의 주소가 다르기 때문입니다.

 

아래 이미지를 참고 해 봅시다.

CallByValue메소드에서는 0x0001 , 0x0002주소값에 각각의 값을 넣고 있죠?

여기서 ChangeValue를 호출할때 두 값을 전달 해 줍니다.

그러면 ChangeValue의 파라미터 변수에는 새로운 주소(0x0010, 0x0011)가 생기고 거기에 호출하면서 넣었던 값(Hong, 20)이 복사가 됩니다.

0x0010, 0x0011안에 있는 값을 아무리 변경해도 원본 주소에 있는 값만 복사되었기 때문에 원본에는 아무런 영향을 끼치지 않습니다.

 

Call by Reference(Pass by Reference)

위에서 언급한 Call by Value처럼 값을 보내는게 아니라 주소값 자체를 복사해서 보내는 개념이라고 보면 됩니다.

주소안에 값이 같이 들어있기 때문에 실질적으로는 주소 + 값을 전부 보내는거죠

이름에서도 언급되었듯이 레퍼런스 타입의 데이터들이 이에 해당됩니다.

 

예제

public class Student {
	String name;
	int age;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

public static void main(String[] args) {

    Student std = new Student();
    std.name = "Hong";
    std.age = 20;

    System.out.println("====== Call By Reference ======");
    CallByReference(std);
}

public static void CallByReference(Student std) {
    System.out.println("Name : " + std.name);
    System.out.println("age : " + std.age);

    ChangeReference(std);

    System.out.println("Changed Name : " + std.name);
    System.out.println("Changed age : " + std.age);
}

    private static void ChangeReference(Student std) {
    System.out.println("=== Change Reference ===");
    std.setName("Lee");
    std.setAge(30);
}

결과

====== Call By Reference ======
Name : Hong
age : 20
=== Change Reference ===
Changed Name : Lee
Changed age : 30

ChangeReference에서 Hong을 Lee로, age를 20에서 30으로 바꾸었는데 이번에는 원본 데이터가 바뀌어진

것을 확인 할 수 있습니다.

 

왜 호출된 함수에서 데이터를 바꾸었는데 원본 값을 바꾸는걸까요?

아래 이미지를 참고 해 봅시다.

0x0001, 0x0002에 값을 넣고있는것은 Call by Value와 동일합니다.

그런데 참조형 데이터를 파라미터로 넘겼을때는 해당 주소값 자체를 복사해옵니다.

주소는 해당 레퍼런스타입의 데이터가 들어있는 Heap영역을 참고합니다.

0x0010에는 0x0001의 주소와 값이 같이 들어있습니다.

0x0011에는 0x0002의 주소와 값이 같이 들어있습니다.

값을 변경하려고 하면 해당 주소를 열어서 값을 변환하기 때문에 결국 원본의 값도 바뀌게 되는 겁니다.

 

이렇게 정리를 해 보았지만 아직도 더 공부가 필요해 보이네요...

이상으로 간단하게 포스팅을 마치도록 하겠습니다.

 

질문이 있는 분들은 댓글을 주시면 환영입니다!

 

728x90
반응형