데블 아니고 데블리

운동,햄버거, 개발 좋아요

🐷💻📝

프로그래밍/자바

[JAVA] 자바는 call by value다..

데블아니고데블리 2024. 5. 24. 21:16

지금 이론 공부를 다시 하고 있는데, 당연하게 생각했던 개념들인데 내가 착각하고 있던 개념이 있어서 블로그에 작성해보려고 한다.

그 중 하나가 call by value 개념인데, call by reference 와 비교해서 면접예상 질문으로 나오기도 한다.

call by value, call by reference 둘 다 변수, 객체 등이 함수의 인자로 들어와 매개변수(parameter)로 전달될 때 어떤 방식으로 전달될 지를 결정하는 방법이다.

 

[착각한 개념]

call by value : 자바의 기본형 타입이 전달되기 때문에 값이 그대로 전달된다(원본 데이터 값 계속 변경)

call by reference : 자바의 참조타입이기 때문에 참조하는 주소값이 복사되어 전달된다(주소값으로 값을 찾는다), 그래서 주소 값으로 전달된 데이터들은 같은 값을 바라보고 있으니 원본 데이터가 영향을 받는다.

 

일단 call by value에 대한 개념을 잘못 이해하고 있었고 정작 자바에서 사용하지 않는 call by reference는 똑바로 이해하고 있었다.

그럼.. 개념을 정정하고 왜 그렇게 생각했는지 생각해야겠다.

 

[정정하기]

call by value : 값에 의한 호출, 값의 복사!

call by reference : 참조에 의한 호출, 주소의 복사!

 

위의 개념을 이해하려면 자바에서 기본형 변수와 참조형 변수의 동작 방식을 이해햐여야 한다

[기본형 변수 : primitive type]

자바에서 값 자체를 가지고 있다. 

기본형 변수는 (int, double, boolean) 등의 원시 타입이다. 함수에 기본형 변수를 전달할 때 그 값의 복사본이 전달된다. 따라서 함수 안에서 값이 변경되어도 원래 변수에도 영향을 주지 않는다.

 

[참조형 변수 : reference type]

참조형 변수는 객체의 주소를 가지고 있다.

자바의 참조형 변수는 배열, 클래스 등의 객체 타입이다. 참수에 참조형 변수를 전달할 때 객체의 주소 값이 복사되어 전달된다. 이 복사된 주소 값을 통해 객체의 상태를 변경할 수 있지만, 참조 자체를 변경하는 것은 원래 객체에 영향을 미치지 않는다 => 이래서 call by value!!

 

그렇다면 예제를 만들면서 이해하는게 좀 더 낫겠다..

public class CallByValueExample {
    public static void main(String[] args) {
        int intValue = 5;
        // 1) intValue의 값이 메서드에 전달된다
        changeValue(intValue);
        // 4) 따라서 원본 값은 변경이 되지 않는다
        System.out.println("변경이 되나? " + intValue); // 5 출력

		// 5) 리턴 값이 있는 경우 intValue 변수의 값 5가 changeValue2 메서드에 전달된다
        int changeValue = changeValue2(intValue);
        
        // 8) 반환된 값 15는 changeValue 변수에 저장되어 있다, 출력하면 변환된 값 15가 출력된다
        System.out.println("리턴 값이 있을 때 " + changeValue); // 15 출력

		// 9) new IntObject()는 새로운 IntObject 인스턴스를 힙 메모리에 생성, intObject 변수는 인스턴스의 참조값을 가짐
        IntObject intObject = new IntObject();
        // 10) intObject 인스턴스의 intObject 필드를 10으로 설정
        intObject.intObject = 10;
       
        // 11) intObject의 참조값을 changeObject 메서드에 전달,참조값의 복사본 보내기
        changeObject(intObject);
        // 14)메서드 호출 후, 원본 IntObject 인스턴스의 intObject 필드 값이 17로 변경
        System.out.println("변경이 되나? " + intObject.intObject); // 17 출력
        
        // 15) 참고용, 새로 인스턴스 획득했을 때 새로 힙메모리에 올림
        IntObject intObject2 = new IntObject();
    	System.out.println("매서드 호출 이후 " + intObject2.intObject); // 5 출력
    }

	// 6) intValue의 복사본을 받는다 
    private static int changeValue2(int intValue) {
    	// 7) 복사본의 값을 15로 변경하고 반환합니다
        intValue = 15;
        return intValue;
    }
	
    // 12) changeObject 복제본을 받음, 복사된 참조값을 통해 원래 객체("10)설명에 나옴") 객체에 접근할 수 있음
    private static void changeObject(IntObject intObject) {
    	// 13) 복사된 참조를 통해 원본(10번) IntObject 인스턴스의 intObject 필드를 17로 변경
        intObject.intObject = 17;
    }

	// 2)intValue의 복사본을 받는다
    private static void changeValue(int intValue) {
    	// 3)복사본의 값은 10으로 변경되지만 원본 변수에는 영향을 주지 않는다
        intValue = 10;
    }
}

class IntObject {
    int intObject = 5;
}

 

main 함수에서 'intObject'변수는 IntObject 객체의 주소를 참조한다.

changeObject함수는 이 참조의 복사본을 인자로 받는다.

함수 내에서 이 복사된 참조(intObject)를 통해 원본 객체의 값을 17로 변경한다

여기서 "원본객체"라는 표현이 너무 헷갈렸다.. new로 생성한 것 부터가 복제본인데 말이다...

 

 

그렇다면 call by reference는 무엇이냐..

원본의 주소값이 공유되서 원본 값이 바뀐다.. 애초에 new 생성할 때 원본 데이터 주소값 가져다 쓴다는 말로 해석하면 될 것이다..

그러면 매 번 값이 바뀌니까 에러가 나면 찾기도 엄청 어렵겠다라는 생각이 드네요..

 

이상입니다