본문 바로가기
JAVA

자바는 Call by value

by se0nghyun2 2023. 1. 17.

나는 아래와 같이 들은 적이 있다.

 

더보기

자바엔 메서드 호출 시 2가지 호출 방식이 있다.

 * Call by Value(값에 의한 호출)

 * Call by Reference(참조에 의한 호출)

 

Call by Value 특징 중 하나는 함수 안에서 인자로  값이 변하여도 호출자의 변수는 변하지 않는다.

그와 반대로,

Call by Reference 의 특징 중 하나는 함수 안에서 인자의  값이 변하면 함수 호출 시 있던 변수에도 반영된다.

덕분에 Call by value와 Call by reference를 변하는 것과 변하지 않는 것으로 이해한 채 여지껏 개발을 진행하였고

그러다가 문제를 만나게 되었다. 


 

<문제 발생>

//Main 클래스 내부
List<String> testList = new ArrayList<>(); //1번
System.out.println("메서드 호출 전: "+ testList.size());

TestService  testService = new TestService();
testService.convertList(testList);

System.out.println("메서드 호출 후: "+ testList.size()); //4번




//TestService 클래스
public class TestService {
    public void convertList(List<String> testList){
        List<String> tempList = new ArrayList<>(); 
        
        tempList.add("1");
        tempList.add("2");
        //2번
       

        testList = tempList; //3번

        System.out.println("메서드 내부: "+ testList.size()); 
    }
}

tempList 생성 후 해당 객체를 testService.converList 호출하여 내부에서 새로운 객체를 할당해주었다.

 

[예상결과]

Call by reference가 적용되었다고 생각했다.

메서드 호출 전: 0,

메서드 내부:2,

메스드 호출 후 :2

 

[실제 결과]

 

 

틀렸네 왜지????

위 흐름을 메모리 구조에 나타내어 보았다.

1번 부분

List<String> testList = new ArrayList<>();

2번

List<String> tempList = new ArrayList<>(); tempList.add("1");&nbsp;&nbsp;tempList.add("2");

3번(중요)

아! convertList 메서드 스택에 testList, tempList 새롭게 주소 할당되었고 스택의 testList(0x1010)엔 tempList(0x2020) 주소값이 들어가 해당 주소값의 값을 바라보게 되었다.

즉 , main의 testList(ox1010) 엔 어떠한 영향도 미치지 못한거였다.

testList = tempList;

4번

마지막


<문제 해결>

아래와 같이 수정하니 정상적으로 동작하였다.

//Main 클래스 내부
List<String> testList = new ArrayList<>(); //1번
System.out.println("메서드 호출 전: "+ testList.size());

TestService  testService = new TestService();
testService.convertList(testList);

System.out.println("메서드 호출 후: "+ testList.size()); //4번




//TestService 클래스
public class TestService {
    public void convertList(List<String> testList){ //2번
 
        testList.add("1");
        testList.add("2");

        System.out.println("메서드 내부: "+ testList.size());  //3
    }
}

1번

List<String> testList = new ArrayList<>();

2번

3번

4번


요약하면

  •  call by reference라고 지칭한 것이 결국은 "주소" 값을 참조하는 거였다.
  • 메소드 호출 시 메서드 스택에 새롭게 할당되는구나.( 2번 그림참고)

 

<개선사항>

스택프레임이라는 걸 알아보고 설명 보충해야 한다.