[자바/알고리즘] Integer 클래스는 call by reference로 동작하는가?

프로그래밍/자바2020. 8. 5. 17:57

오늘도 간단하지만.. 생각좀 해봐야할 문제에 대해 짚고 넘어가겠습니다.

 

https://leetcode.com/problems/maximum-depth-of-binary-tree/ 의 문제에서.. tree의 최대 깊이를 구하기 위해 아래와 같은 간단한 코드를 짰습니다.

 

class Solution {
    public int maxDepth(TreeNode root) {
        
        //Integer maxDepth = new Integer(); // no suitable constructor found for Integer(no arguments)
        Integer maxDepth = new Integer(0); 
        dfs(root, 0, maxDepth);
        
        return maxDepth;
    }
    
    public void dfs(TreeNode root, int depth, Integer maxDepth){
        if(root == null){
            return;
        }
        
        maxDepth = Math.max(maxDepth, depth+1);
        System.out.println("maxDepth = " + maxDepth + ", val = " + root.val);
        
        dfs(root.left, depth+1, maxDepth);
        dfs(root.right, depth+1, maxDepth);
        
    }
}

저는 전역변수를 사용하지 않고 구현을 하고 싶었습니다.

그래서 java에서 class는 c언어의 포인터처럼 동작하니까 primitive type인 int 대신에 claa형인 Integer를 인자로 주면 call by reference로 동작할 것이라고 생각했습니다.

 

 

maxDepth = 1, val = 3
maxDepth = 2, val = 9
maxDepth = 2, val = 20
maxDepth = 3, val = 15
maxDepth = 3, val = 7

 

dfs함수 내에서는 maxDepth가 잘 동작하는 것처럼 보이지만, dfs()를 호출한 maxDepth()에서 출력되는 Integer maxDepth의 값은 0이었습니다.

 

stackoverflow에서 검색을 좀 해보면.. Integer클래스도 call by value로 동작한다느니.. 엄밀히 말하면 call reference by value?로 동작한다느니.. 좀 명확하지 않은 것 같습니다.

 

다른 홈페이지에서 찾아보면 아래의 글이 있습니다.

(https://www.techiedelight.com/pass-integer-reference-java/)

 

We know that Java is pass by value and it is not possible to pass primitives by reference in Java. Also Integer class is immutable in Java and Java objects are references that are passed by value. So an Integer object points to the exact same object as in the caller and but no changes can be made to the object which gets reflected in the caller function.

 

자바에서 Integer 클래스는 수정이 불가능하며 자바 객체는 값으로 전달되는 reference(주소값)이다. 그래서 (함수 안의) Integer 객체는 호출되는(예: Main함수) 쪽과 같이 정확히 같은 객체를 가르킬 수 있으나 호출되는 쪽에 영향을 주는 수정은 불가능하다.

 

살짝 헷갈릴 수 있는데 String 클래스와 같이 두고? 생각해보면 좀 더 쉬운 것 같습니다. 비교해보니 서로 같네요.

String을 다룰 때 값을 자주 바꿔야 하면 StringBuilder를 사용하라고 합니다.

왜냐하면 String 역시도 immutable(수정 불가능)이기 때문에 기존의 String 객체에 다른 값을 할당하게 되면.. 기존의 메모리가 수정되는 것이 아니라 새로운 메모리에 값이 할당되면서 expensive한 동작이 되기 때문입니다.

 

아래의 간단한 예제를 보겠습니다.

public int caller() {        
        String test = "test";
        System.out.println("caller Before: test = " + test + ", addr = " + Integer.toHexString(test.hashCode()));
        stringTest(test);
        System.out.println("caller After: test = " + test + ", addr = " + Integer.toHexString(test.hashCode()));
    }
    
    public void stringTest(String test){
        System.out.println("stringTest Before: test = " + test + ", addr = " + Integer.toHexString(test.hashCode()));
        test = "in StringTest";
        System.out.println("stringTest After: test = " + test + ", addr = " + Integer.toHexString(test.hashCode()));
        
    }


caller Before: test = test, addr = 364492
stringTest Before: test = test, addr = 364492
stringTest After: test = in StringTest, addr = d7b7963e
caller After: test = test, addr = 364492

 

결과값은 위와 같습니다.

hashCode()함수를 이용해 대략적인 주소값도(식별자로 쓰이는 값) 찍어봤습니다.

 

함수 인자로 값이 제대로 전달됐으나.. 내부에서 test = "in StringTest"; 코드를 만나면서 함수 내부의 test는 다른 메모리를 가르키게 됩니다. c언어로 생각해보면 함수 내부에서 malloc으로 새로운 메모리 공간을 할당 받았다고 보면 되겠네요.

 

이러한 점을 생각해보면 제가 애당초 짰던 코드에서 callee에 있는 아래의 코드 때문에 원하는대로 동작하지 않습니다.

maxDepth = Math.max(maxDepth, depth+1);

처음에는 함수 내부에서도 maxDepth는 caller와 동일한 Integer 객체를 가르키겠지만..

값을 수정하게 되면.. String처럼 새로운 주소를 할당받게 되어서 caller와 callee는 서로 다른 객체를 가르키게 됩니다.

 

어떻게 보면 사소한 부분이지만.. ㅎㅎ 제대로 짚고 넘어가니 좋네요.

 

아차.. 그리고 해결법에 대한 내용이 궁금하신 분들은 아래의 글을 참고 바랍니다.(영어)

https://www.techiedelight.com/pass-integer-reference-java/

 

How to pass integer by reference in Java - Techie Delight

In this post, we will see how to pass integer by reference in Java... We know that Java is pass by value and it is not possible to pass primitives by reference in Java. Also Integer class is immutable in Java and Java objects are references that are passed

www.techiedelight.com

 

작성자

Posted by 드리머즈

관련 글

댓글 영역