이 글을 읽기 전에, 여러분의 경험과 이해를 바탕으로 먼저 Java 함수의 매개변수 전달 방법에 대해 생각하고 선택할 수 있습니다.
A. 값으로 전달되나요?
B. 참조로 통과되었나요?
C. 일부는 값으로, 일부는 참조로?
여기서는 아직 정답을 발표하지 않습니다. 간단한 예를 통해 직접 답을 찾아보겠습니다.
1. 먼저 유형 값을 정의하십시오.
공개 정적 클래스 값 { 개인 문자열 값 = "값"; 공개 문자열 getValue() { 반환 값 } 공개 void setValue(문자열 값) { this.value = 값 }
2. newValue 및 수정값 함수 두 개를 작성합니다. newValue는 입력 매개변수를 새 객체로 가리키고, 수정값은 입력 매개변수의 setValue 메소드를 호출하여 객체의 값을 수정합니다.
public static void newValue(Value value) { value = new Value(); value.setValue("새 값") System.out.println("newValue에서 HashCode = " + value.hashCode() + ", value = " + value.getValue()); } public static void 수정 값(값 값) { value.setValue("새 값"); System.out.println("수정 값에서, HashCode = " + value.hashCode() + ", value = " + value.getValue()); }
3. 간단한 테스트 코드
public static void main(String[] args) { Value value1 = new Value(); System.out.println("수정 전, HashCode = " + value1.hashCode() + ", value = " + value1.getValue() ); // value1을 새 Value 객체로 지정 newValue(value1) System.out.println("수정 후 HashCode = " + value1.hashCode() + ", value = " + value1.getValue() + "/n"); Value value2 = new Value()("수정 전, HashCode = " + value2.hashCode() + ", value = " + value2.getValue()); // 객체의 set 메소드를 사용하여 객체의 내부 값을 수정합니다.modifyValue(value2); System.out.println("수정 후 HashCode = " + value2.hashCode() + ", 값 = " + value2.getValue()) }
4. 실행 결과 로그:
수정 전, HashCode = 12677476, 값 = 값 newValue에서 HashCode = 33263331, 값 = 새 값 수정 후, HashCode = 12677476, 값 = value 수정 전, HashCode = 6413875, 값 = value 수정 전, HashCode = 6413875, 값 = value 새 값 수정 후 HashCode = 6413875, 값 = 새 값
5. 결과 분석:
위의 코드는 매우 일반적인 프로그래밍 패턴입니다. 정의 | 저장 | 주변에서 값이나 개체를 가져오고 개체를 메서드에 매개 변수로 전달하고 메서드에서 개체의 속성과 동작을 수정합니다. 하지만 newValue와 adjustValue 두 메소드의 수정 방법은 다릅니다. 메소드가 호출된 후 객체는 외부에서 매우 다르게 보입니다! 이 차이를 어떻게 이해해야 할까요? 먼저 값에 의한 전달과 참조에 의한 전달의 개념을 검토해 보겠습니다.
* 값으로 전달한다는 것은 함수에 인수를 전달할 때 함수가 원래 값의 복사본을 받는 것을 의미합니다. 따라서 함수가 매개변수를 수정하면 복사본만 변경되고 원래 값은 변경되지 않습니다.
* 참조로 전달한다는 것은 인수가 함수에 전달될 때 함수가 값의 복사본이 아닌 원래 값의 메모리 주소를 받는 것을 의미합니다. 따라서 함수가 매개변수를 수정하면 매개변수의 원래 값(함수 블록 외부의 호출 코드에 있음)도 변경됩니다.
정답: A - Java 함수는 매개변수를 값으로 전달합니다!
로그를 분석합니다.
* 로그 출력의 첫 번째 섹션에서는 value1 매개변수가 newValue 메소드 내부의 새 객체를 가리키도록 변경되고, 새 객체의 hashCode 및 값이 출력됩니다. 그러나 newValue 메소드 도메인을 벗어나면 아무런 변화가 없습니다. 이는 기본 메소드에서 value1에 발생합니다. 이는 값 전달의 정의 및 특성을 따르며 참조로 전달되는 경우 newValue(Value value) 메소드를 호출한 후 value1이 변경되어야 합니다.
* 두 번째 로그 출력은 value2가 수정 값 메소드 내에서 setValue 작업을 수행함을 보여줍니다. hashCode는 변경되지 않지만 값은 수정 값 메소드 도메인을 떠난 후 기본 메소드에서 변경됩니다. C++를 사용해 본 사람들은 이 현상을 다음과 같이 쉽게 이해할 수 있습니다. 함수 매개변수를 참조로 전달합니다! 이는 C++의 참조로 전달하는 것과 매우 유사하기 때문입니다! 그러나 이것이 바로 오해에 빠질 가능성이 가장 높은 곳입니다!
두 로그의 서로 다른 현상 뒤에 숨은 원리는 Java 언어가 매개변수를 값으로 전달하고 객체를 참조로 전달한다는 것입니다. Java에서 작동하는 객체는 실제로 작동 객체에 대한 참조이며 객체 자체는 "힙"에 저장됩니다. 객체의 "참조"는 레지스터 또는 "스택"에 저장됩니다.
의사코드는 newValue 메소드와 수정값 메소드의 차이점을 설명합니다.
newValue{ Value_ref2 = value_ref1; // 값으로 참조 value_ref1을 전달하고 value_ref1의 복사본을 얻습니다. value_obj2 = new Value(); // value_obj2가 "힙"에서 생성되고 초기화됩니다. value_ref2 -> value_obj2는 // value_obj2 value_ref2 - >value_obj2.setValue("xxx") // value_obj2 값이 수정되었습니다. printValueObj2(); // 여기에 인쇄되는 것은 obj2의 값입니다. "); // value_obj1의 값이 수정됩니다. printValueObj1(); // 여기에 출력되는 것은 obj1의 값입니다.}
충분히 명확합니다! value1_ref1이 함수에 매개변수로 전달되면 value1_ref2의 복사본이 함수 도메인에서 사용하기 위해 먼저 복사됩니다. 이때 두 참조는 모두 newObject 함수의 동일한 value_obj 코드를 가리킵니다. ] 실제로 value1_ref1은 새 개체 value_obj2를 가리킵니다. 이후의 설정 작업은 모두 새 개체에 대한 작업입니다.
값으로 매개변수 전달
메소드를 호출할 때 매개변수를 제공해야 하며, 매개변수 목록에 지정된 순서대로 제공해야 합니다.
예를 들어, 다음 메소드는 연속해서 n번 메시지를 인쇄합니다.
public static void nPrintln(String message, int n) { for (int i = 0; i < n; i++) System.out.println(message);}
예제 다음 예제에서는 값 전달의 효과를 보여줍니다.
이 프로그램은 두 변수를 교환하는 메서드를 만듭니다.
public class TestPassByValue { public static void main(String[] args) { int num1 = 1; int num2 = 2; System.out.println("스왑 메서드 전, num1은 " + num1 + "이고 num2는 " + num2) ; // 스왑 메소드 호출 swap(num1, num2); System.out.println("스왑 메소드 이후 num1은 " + num1 + " and num2 is " + num2) } /** 두 변수를 교환하는 방법*/ public static void swap(int n1, int n2) { System.out.println("/tInside the swap method"); .out.println("/t/t교체 전 n1은 " + n1 + " n2는 " + n2); // n1과 n2의 값을 교환합니다. int temp = n1 = n2; n2 = temp; System.out.println("/t/t 교체 후 n1은 " + n1 + "입니다. }}
위 예제의 컴파일 및 실행 결과는 다음과 같습니다.
스왑 방식 전 num1은 1, num2는 2 스왑 방식 내부 스왑 전 n1은 1 n2는 2 스왑 후 n1은 2 n2는 1 스왑 방식 후 num1은 1, num2는 2
두 개의 매개변수를 전달하는 swap 메서드를 호출합니다. 흥미롭게도 실제 매개변수의 값은 메소드가 호출된 후에도 변경되지 않습니다.