본문 바로가기

CS study/java

예시를 통해 알아보는 Java의 Call by Value, Call by Reference 개념

 

개요

java에서는 call by value로 jvm이 동작하고, c++등에서는 call by reference로 참조에 의한 복사로 객체들이 생성되고 동작된다고 한다.

(물론, 최신 트렌드에서는 이를 적당히 합하여 사용한다. 원론적인 이야기이다.)

 

오늘은 이 개념에 대해 의의와 실제 동작 과정에서 어떻게 이루어지는지 알아볼 것이다.

 

한 눈에 보는 두 개념의 차이

참조 : https://loosie.tistory.com/486

 

요약 : 

참조에 의한 호출은 그냥 무조건 메모리 주소 자체를 참조하는 거고,

값에 의한 호출은 그 값의 복사본을 만들어서(만들때 원본을 참조) 운영한다는 차이이다.

 

Call by reference : 원본 데이터 자체를 직접 조작. 

Call by value : 원본 데이터를 보호하면서 독립적인 복사본을 통해 작업을 수행.

 

call by value : 값을 복사해서 전달하는 '값에 의한 호출(Call by Value)'

Java에서는 모든 함수 호출이 '값에 의한 호출'로 이루어진다.

기본 타입(Primitive)은 실제 값을 복사해서 전달하고, 객체는 참조값을 복사해서 전달한다.

기본 타입(Primitive Types)의 전달

Java에서 기본 타입(int, float, double 등)의 변수는 직접적으로 값을 전달한다.

함수로 전달될 때, 그 값의 복사본이 생성되고 함수 내에서 이 복사본이 사용된다. 원본 변수는 변경되지 않는다.

 

이는 JVM에서 기본형의 경우 Stack 영역에 저장되는데, 이 경우 같은 메모리 주소에 접근하지 않는다.

기본형 타입을 복사하는 순간 이 Stack 영역에 복사된 값을 가진 새로운 메모리 공간이 할당된다.

 

핵심은 복사되어 새로운 스택 메모리에 새 변수가 할당된다고 할 수 있겠다.


객체(참조형 타입)의 전달

객체의 경우는 이전과 다르다.

1. 객체의 경우, 객체의 실제 데이터가 아닌 객체의 '참조값(reference)'이 함수에 전달된다.

즉, Java에서 객체를 함수에 전달할 때, 전달되는 것은 객체의 실제 데이터가 아니라 그 객체를 가리키는 참조값이다. 이 참조값은 객체가 저장된 메모리 주소를 의미한다.

 

2. 이 참조값을 통해 함수 내에서 객체를 조작할 수 있다

그러나 전달된 것은 객체 자체가 아닌 '참조값'이기 때문에, 이는 기술적으로 '값에 의한 호출'(call-by-value)로 분류된다.

 

참조형 타입의 예시 : 객체 조작

 

1. A라는 객체(내부 요소에 int a;가 있다고 하자.)가 있다.
2. method(A input); 에 내가 선언한 A 객체를 넣는다. 이후 해당 메서드를 실행한다면?
3. method 안의 입력 파라미터인 A 객체(편의상 A*라 호칭)가 '생성'된다. 

하지만 생성된 A*객체 역시 JVM 내부에서 원본 A가 저장된 주소값을 복사했다. (그래서 A와 A*는 같은 메모리 주소를 바라보고 있다.)
4. 결과적으로 복사된 A*의 값을 변경하면 A의 정보가 저장된 메모리의 값이 변경된다.

 

이를 코드로 살펴보면 다음과 같을 것이다.

import java.util.*;
import java.io.*;

public class Main {

    //테스트용 MyClass 객체가 있다고 가정해보자.
    static class MyClass {
    	int value = 100; //초기 값은 100이다.
    }
    
    public static void main(String[] args) throws IOException {
    	MyClass firstMyClass = new MyClass(); //1. 새로운 객체를 생성하고, JVM에 저장하자.
    	
    	myMethod(firstMyClass); //2. 내가 만든 (1) 객체를 파라미터로 넣었다.
    	
    	System.out.println(firstMyClass.value); //5. 메모리 내부 값 변경으로 영향을 받아 -1이 출력된다.
    }
    
    static void myMethod(MyClass myClass) {
    	//3. 하지만 함수 호출이 되는 순간, 입력 파라미터인 myClass는 새로 생성된다.
    	//생성 과정에서 myClass는 firstMyClass의 값을 '복사' 하여 새로 생성된다.
    	
    	myClass.value = -1; //내부 프로퍼티를 수정하였다.
    	
    	//4. 분명 새로 만든 myClass의 값을 변경하였지만, 
    	//firstMyClass와 myClass의 메모리 주소는 '동일'하다.
    	//그렇기에 firstMyClass 역시 메모리 변경으로 인해 값이 변경된다.
    }

}

 

 

3. 함수 내에서 전달받은 참조값을 사용하여 객체의 상태를 변경할 수 있다.

함수 내에서 참조값 자체를 변경해도 원본 참조 변수에는 영향을 미치지 않는다.
조금 더 풀어서 이야기하자면, 다음과 같다.

 

1. A라는 객체가 있다.

2. 이 A를 참조한 객체 A*이 함수 내부에서 새로 복사된다.

3. A*의 참조 주소를 B로 바꿔도, A 자체에는 영향이 없다. (A는 그대로 A의 메모리 주소를 바라보고 있다.)

 

이를 예시 코드로 살펴보자.

 

public class MyClass {
    int value;
}

public static void main(String[] args) {
    MyClass obj = new MyClass();    //원본
    obj.value = 10;
    changeReference(obj);
    System.out.println(obj.value);  // 여전히 10을 출력
}

public static void changeReference(MyClass ref) {
    ref = new MyClass(); //새로운 참조 주소를 생성했다. 하지만 원본은 아무런 상관이 없다.
    ref.value = 20;
}

 

 

 

번외 : call by reference 개념 

Call by Reference는 함수 호출 시 인자로 전달되는 변수의 참조(메모리 주소)가 직접 전달되는 방식이다.

이 방식에서는 함수 내에서 인자의 참조를 통해 원본 변수의 값을 변경할 수 있다.

하지만, Java는 순수한 Call by Reference를 지원하지 않는다.

 

Call by value와 Call by Reference의 동작 과정 차이

https://yoojin99.github.io/cs/Call-by-Value-Call-by-Reference/

 

이전 설명의 연장선.

Call by Value일 경우 기본형 타입 내부 값은 바뀌지 않는다!! (Stack에 새로 num1, num2가 기본형으로 추가되었으므로)

 

 

https://yoojin99.github.io/cs/Call-by-Value-Call-by-Reference/

 

하지만 참조에 의한 복사의 경우 다음과 같은 상황에서 값이 바뀐다.

처음부터 메모리 자체를 참조하기 때문이다!

 

이 경우 다음과 같은 장단점을 가지게 된다.

  • 장점 : 복사하지 않고 직접 참조를 하므로 빠르다.
  • 단점 : 직접 참조를 하기 때문에 원래 값이 영향을 받는다.

 

참조

https://testbook.com/key-differences/difference-between-call-by-value-and-call-by-reference

 

Difference Between Call by Value and Call by Reference in Programming

This article explains the differences between Call by Value and Call by Reference, two methods of invoking functions in programming. It discusses how parameters are passed in these methods, their effects, and the programming languages that support them.

testbook.com

 

https://loosie.tistory.com/486

 

[Java] 자바가 언제나 Call By Value인 이유 (Call By Reference X)

Intro 시작하기 앞서 CS이론에서는 "Call by value"와 "Call by reference"를 구분하는 것은 더 이상 쓸모없다고 한다. 왜냐하면 "Call By Reference"은 이제 트렌드에 뒤쳐진 기술로 선호도 굉장히 낮아져 최신

loosie.tistory.com

 

https://yoojin99.github.io/cs/Call-by-Value-Call-by-Reference/

 

Call by value와 Call by reference의 차이

내가 하고 싶은 것을 하는 블로그

yoojin99.github.io