-
Java는 모두 call by value다?알고리즘과 언어/java 2022. 3. 23. 05:26
얼마 전 개발자 형에게 Java가 모두 call by value라는 이야기를 들었다.
C/C++에 익숙했던 나는 이해가 되지 않았다.
'Call by reference가 없으면 어떻게 내부의 값을 변경하지?'
'Java에서도 분명 함수로 주소값을 주고 받을 일이 있을텐데..' 등등 다양한 의문이 생겼다.
우선, 간단한 Swap에 대해서 찾아봤다.
자바는 포인터가 없어 간단한 Swap 구현 코드도 복잡하다.
1. 배열을 이용하는 방법
public class Main { public static void swap(int[] arr) { int temp = arr[0]; arr[0] = arr[1]; arr[1] = temp; } public static void main(String[] args) { int a = 10; int b = 20; int[] arr = {a, b}; swap(arr); System.out.println(arr[0] + " " + arr[1]); } }
2. 참조타입인 객체를 이용하는 방법
public class Main { int num; public static void main(String[] args) { Main A = new Main(1); Main B = new Main(2); System.out.println(A.num); System.out.println(B.num); Swap(A, B); System.out.println(A.num); System.out.println(B.num); } public Main(int a) { num = a; } public static void Swap(Main A, Main B) { int tmp = A.num; A.num = B.num; B.num = tmp; } }
3. 연산의 우선순위를 이용한 방법
public class Main { private static int trickSwap(int original, int willBeChanged) { return original; } public static void main(String args[]) { int a = 10; int b = 20; // 호출 시 전달인자에서 a = b, 바뀌기 전의 a를 반환하므로 b = a b = trickSwap(a, a = b); System.out.println(a + " " + b); } }
'2번 같은 경우에는, 객체를 주고 받고 객체 내부에 접근하여 값을 바꿨으니
주소값을 전달받은 call by reference인 것이 아닐까?' 라고 생각했다.
다음 동영상을 보며 왜 객체를 넘기는 것이 call by reference와 차이가 있는지를 알게 됐다.
1. 앞서 swap 예시처럼 JAVA는 파라미터로 객체를 받아서 멤버 변수를 바꿀 수 있다. (참조 타입을 사용하며 마치 call by reference처럼 보일 수 있다.)
2. 그러나 이것은 단지 참조값을 복제(call by value)했기에 같은 메모리를 가리키고 있기 때문인 것이다.
(너무 억지 아닌가? 포인터도 주소값을 숫자로 받는 것 뿐인데)
** 하지만 참조값과 주소값은 다르다 **
참조값은 주소와 연결된 Key일 뿐이며 VM이 생성해주는 값이다.
3. JAVA에서는 참조 타입에 새로운 값을 할당한다면(new) 메모리가 새롭게 할당될 뿐 아니라 새로운 참조값이 할당된다(VM에 의해).
4. 만일 call by reference라면 주소값이 변경되지 않은 채 새로운 값을 할당할 수 있어야 할 것이다. (주소값을 자유롭게 사용할 수 있어야 할 것)
5. 때문에 JAVA는 모든 것들을 value로 주고 받는 언어다. (참조값을 주고 받는 것)
참조값은 아래 설명하겠습니다.
실행 예시
public class Main { public static void main(String[] args) { Cheese myCheese = new Cheese(); myCheese.setLevel(10); //값 세팅 increaseLevel(myCheese); // 값 올리기 System.out.println(ntCheesse.getLevel); // 값 출력 } private static void increaseLevel(Cheese cheese) //주소값을 복사하여 가져온다. { cheese = new Cheese(); //새롭게 선언하면 새로운 메모리가 생성되는 주소값이 바뀐다. 그리고 mycheese에 반영되지 않는다 cheese.setLevel(777); } } //10을 출력한다.
결론
C++ 에서는 new를 이용해서 메모리를 생성하면 주소 그 자체를 직접 넘겨준다.주소를 저장하기 위한 포인터 변수를 사용하여 C++에서는 사용자가 주소를 직접 처리한다.
하지만 자바에서는 메모리 주소를 바로 주지 않는데, 즉 인스턴스의 메모리 주소 대신 주소와 연결된 참조값을 할당받는다.
(Ex. 객체를 출력하게되면 나오는 객체@숫자들 )
JAVA에서는 메모리가 생성되면 내부 인덱스 테이블(Index Table)에 주소를 맵핑하는 참조값이 하나씩 만들어진다.
참조값은 누가 만들까?
참조값은 가상머신(VM)에서 자동으로 생성되며, 객체 구분을 위한 유일한 Key가 된다.
@ 뒤에 나오는 4바이트의 16진수의 숫자값을 의미한다.
** 그렇기 때문에 call by reference 로 보이는 것은 메모리 주소 정보를 담은 참조값을 복사하여 접근 가능했기에 가능했던 일이며,
참조값 복사도 값 복사에 해당되며 JAVA에서는 값에 의한 호출(Call by Value)만 존재한다.
레퍼런스
https://dohe2014.tistory.com/18
참조(reference)와 참조변수(reference variable)
연산자 new는 클래스의 새로운 인스턴스에 대한 참조(reference)를 리턴합니다. The new operator returns a reference to a new instance of a class. * 여기서 참조(reference)는 참조변수(reference variable)..
dohe2014.tistory.com
Java | Java에서 Swap 함수 구현 (Java의 call-by-reference)
Call-by-Value와 Call-by-Reference 1. call-by-value 메소드의 파라미터로 호출자(caller)가 제공한 값을 전달하는 방식입니다. 파라미터 값이 복사되어 전달되므로, 호출자의 값은 수정되지 않습니다. 자바는
zuyo.tistory.com
https://velog.io/@jeong11/Java-Reference-type-2qoln8nu
[Java] 참조타입_참조변수(Reference type)
참조 타입 : 기본 타입을 제외하고 배열, 열거, 클래스, 인터페이스 등을 말한다. 참조 타입의 변수에는 객체의 번지가 저장된다.
velog.io
'알고리즘과 언어 > java' 카테고리의 다른 글
jpa양방향 매핑 시 무한루프 ... (0) 2023.06.04 ConcurrentHashMap (0) 2022.01.15