Java의 메소드 매개 변수에 키워드 "final"을 사용해야하는 이유는 무엇입니까?


381

메소드 매개 변수에 사용될 때 final키워드가 실제로 편리한 위치를 이해할 수 없습니다 .

익명 클래스의 사용, 가독성 및 의도 선언을 제외하면 거의 가치가 없어 보입니다.

일부 데이터를 일정하게 유지하는 것은 생각만큼 강력하지 않습니다.

  • 매개 변수가 프리미티브 인 경우 매개 변수가 메소드에 값으로 전달되므로 변경되지 않고 범위를 벗어나지 않습니다.

  • 참조로 매개 변수를 전달하는 경우 참조 자체는 로컬 변수이며 참조가 메소드 내에서 변경되면 메소드 범위 외부에서 영향을 미치지 않습니다.

아래의 간단한 테스트 예제를 고려하십시오. 이 테스트는 메소드가 주어진 참조의 값을 변경했지만 효과가 없습니다.

public void testNullify() {
    Collection<Integer> c  = new ArrayList<Integer>();      
    nullify(c);
    assertNotNull(c);       
    final Collection<Integer> c1 = c;
    assertTrue(c1.equals(c));
    change(c);
    assertTrue(c1.equals(c));
}

private void change(Collection<Integer> c) {
    c = new ArrayList<Integer>();
}

public void nullify(Collection<?> t) {
    t = null;
}

101
용어에 대한 하나의 빠른 요점-Java에는 참조를 통한 전달이 전혀 없습니다. 동일하지 않은 값으로 참조 전달 합니다. 참조 의미론으로 진정한 전달을 사용하면 코드 결과가 다를 수 있습니다.
Jon Skeet

6
기준 별 통과와 기준 별 통과 기준의 차이점은 무엇입니까?
NobleUplift

C 컨텍스트에서 그 차이를 설명하는 것이 더 쉽습니다 (적어도 나를 위해). <code> int foo (int bar) </ code> 와 같은 메소드에 포인터를 전달하면 해당 포인터가 값으로 전달됩니다. 의미는 복사되어 있으므로 <code> free (bar); bar = malloc (...); </ code> 그런 다음 방금 정말 나쁜 일을했습니다. 무료 호출은 실제로 가리키는 메모리 덩어리를 해제합니다 (따라서 전달 한 포인터가 매달려 있습니다). 그러나 <code> int foo (int & bar) </ bar>는 코드가 유효하고 전달 된 포인터의 값이 변경됨을 의미합니다.
jerslan

1
첫 번째 int foo(int* bar)는 마지막 이어야 합니다 int foo(int* &bar). 후자는 참조로 포인터를 전달하고 전자는 값으로 참조를 전달합니다.
jerslan

2
@Martin, 제 생각에는 좋은 질문입니다 . 질문의 제목과 이유에 대한 설명과 포스트 내용을 참조 질문이 요구됩니다. 어쩌면 나는 여기서 규칙을 오해하고 있지만 이것이 "메소드에서 최종 매개 변수의 사용"을 검색 할 때 원하는 질문 입니다.
Victor Zamanian 2016 년

답변:


239

변수 재 할당 중지

이 답변은 지적으로 흥미롭지 만 간단한 대답은 읽지 못했습니다.

컴파일러에서 변수가 다른 객체에 다시 할당되지 않도록하려면 final 키워드를 사용하십시오 .

변수가 정적 변수, 멤버 변수, 로컬 변수 또는 인수 / 매개 변수인지에 관계없이 효과는 완전히 동일합니다.

실제로 효과를 보자.

두 개의 변수 ( argx )에 서로 다른 객체를 재 할당 할 수 있는이 간단한 방법을 고려하십시오 .

// Example use of this method: 
//   this.doSomething( "tiger" );
void doSomething( String arg ) {
  String x = arg;   // Both variables now point to the same String object.
  x = "elephant";   // This variable now points to a different String object.
  arg = "giraffe";  // Ditto. Now neither variable points to the original passed String.
}

지역 변수를 final 로 표시하십시오 . 컴파일러 오류가 발생합니다.

void doSomething( String arg ) {
  final String x = arg;  // Mark variable as 'final'.
  x = "elephant";  // Compiler error: The final local variable x cannot be assigned. 
  arg = "giraffe";  
}

대신 매개 변수를 final 로 표시해 봅시다 . 컴파일러 오류가 발생합니다.

void doSomething( final String arg ) {  // Mark argument as 'final'.
  String x = arg;   
  x = "elephant"; 
  arg = "giraffe";  // Compiler error: The passed argument variable arg cannot be re-assigned to another object.
}

이야기의 교훈:

변수가 항상 같은 객체를 가리 키도록하려면 변수를 final로 표시하십시오 .

인수를 다시 할당하지 마십시오

좋은 프로그래밍 방법 (모든 언어로)으로, 호출 메소드가 전달한 오브젝트 이외의 오브젝트에 매개 변수 / 인수 변수를 다시 지정 해서는 안됩니다 . 위의 예에서 절대로 줄을 쓰지 않아야합니다 arg =. 인간은 실수를 저지르고 프로그래머는 인간이므로 컴파일러에게 도움을 요청하십시오. 컴파일러가 이러한 재 할당을 찾아 플래그를 지정할 수 있도록 모든 매개 변수 / 인수 변수를 'final'로 표시하십시오.

회고

다른 답변에서 언급했듯이 ... 프로그래머가 배열의 끝을지나 읽는 것과 같은 멍청한 실수를 피하도록 돕는 Java의 원래 설계 목표를 감안할 때 Java는 모든 매개 변수 / 인수 변수를 '최종'으로 자동 시행하도록 설계되어야합니다. 즉, 인수는 변수가 아니어야합니다 . 그러나 뒤늦은 시각은 20/20 비전이며 Java 디자이너는 당시 손을 가득 채웠습니다.

따라서 항상 final모든 인수에 추가 합니까?

final선언되는 각각의 모든 메소드 매개 변수에 추가해야합니까 ?

  • 이론적으로는 그렇습니다.
  • 실제로는 아닙니다. method 메소드의 코드가 길거나 복잡한 경우에만
    추가하십시오 final. 인수는 로컬 또는 멤버 변수로 오인되어 재 할당 될 수 있습니다.

인수를 다시 할당하지 않는 관행을 사면 각각에 인수를 추가하는 경향이 있습니다 final. 그러나 이것은 지루하며 선언을 조금 더 읽기 어렵게 만듭니다.

인수가 지역 변수 또는 멤버 변수가 아닌 인수 인 짧은 간단한 코드의 경우에는을 추가하지 않아도 final됩니다. 코드가 분명하고 나나 다른 프로그래머가 실수로 인수 변수를 인수가 아닌 다른 인수로 잘못 리팩토링하거나 리팩토링 할 가능성이 없다면 귀찮게하지 마십시오. 내 자신의 작업에서 final인수가 로컬 또는 멤버 변수로 착각 할 수있는 더 길거나 관련된 코드 만 추가 합니다.

완전성을 위해 추가 된 또 다른 사례

public class MyClass {
    private int x;
    //getters and setters
}

void doSomething( final MyClass arg ) {  // Mark argument as 'final'.

   arg =  new MyClass();  // Compiler error: The passed argument variable arg  cannot be re-assigned to another object.

   arg.setX(20); // allowed
  // We can re-assign properties of argument which is marked as final
 }

23
"모든 프로그래밍 언어에서 좋은 프로그래밍 방법으로 매개 변수 / 인수 변수 [..]를 다시 할당해서는 안됩니다."죄송합니다. 인수 재 할당은 전달되는 인수의 양이 메소드 서명에 의해 지시되지 않는 Javascript와 같은 언어의 표준 관행입니다. 예를 들어, "function say (msg)"와 같은 서명이 주어지면 사람들은 "msg"인수가 할당되었는지 확인합니다 : "msg = msg || 'Hello World!';". 세계 최고의 자바 스크립트 프로그래머가 모범 사례를 깨뜨리고 있습니다. jQuery 소스를 읽으십시오.
Stijn de Witt

37
@StijndeWitt이 예제는 인수 변수를 다시 할당하는 문제를 보여줍니다. 당신 잃게 정보를 얻은 아무것도 대가로 : (A)는 당신은 당신은 호출 방법 ( '! 안녕하세요'발신자 패스를 않았거나 우리가 기본 않았다)의 의도를 잃은 원래의 값이, (B)를 통과 잃었습니다. a와 b는 모두 테스트, 긴 코드 및 나중에 값이 더 변경 될 때 유용합니다. 나는 내 진술을지지한다. arg vars는 결코 재 할당 되어서는 안된다 . 코드는 다음과 같아야합니다 message = ( msg || 'Hello World"' ). 별도의 var를 사용 하지 않는 이유는 없습니다 . 유일한 비용은 몇 바이트의 메모리입니다.
Basil Bourque

9
@Basil : 더 많은 코드 (바이트)와 Javascript가 중요합니다. 무겁게. 많은 것들과 마찬가지로 의견에 근거합니다. 이 프로그래밍 방식을 완전히 무시하고 여전히 우수한 코드를 작성하는 것은 전적으로 가능합니다. 한 사람의 프로그래밍 연습이 모든 사람의 연습이되는 것은 아닙니다. 당신이 할 모든 것을 지키십시오, 나는 어쨌든 다르게 쓰도록 선택합니다. 그렇게하면 나쁜 프로그래머입니까, 아니면 코드가 나쁜 코드입니까?
Stijn de Witt

14
를 사용하면 message = ( msg || 'Hello World"' )나중에 실수로을 사용할 위험이 있습니다 msg. 내가 의도 한 계약이 "아니오 / 널 / 정의되지 않은 arg를 가진 행동은 전달과 구별 할 수없는 행동 "Hello World""일 때, 함수의 초기에 계약을 이행 하는 것이 좋은 프로그래밍 관행이다. [이것은 처음부터 재할 if (!msg) return myfunc("Hello World");당하지 않고 달성 할 수 있지만 여러 인수로 다루기 어려워집니다.] 드물게 함수의 논리가 기본값 사용 여부를 신경 써야하는 경우가 아니라 특별한 센티넬 값을 지정하는 것이 좋습니다 (공개) .
Beni Cherniavsky-Paskin

6
BeniCherniavsky - Paskin @ 당신이 설명하는 위험은 때문에 사이의 유사성이다 message하고 msg. 그러나 그가 그것을 processedMsg추가 맥락을 제공 하는 것과 같은 것으로 부르면 실수의 가능성은 훨씬 낮습니다. 그가 "어떻게" 말하지 않는지 에 집중 하십시오. ;)
알파 신

230

때로는 변수가 변경되지 않는다는 것을 명확하게 (가독성을 위해) 밝히는 것이 좋습니다. 다음은 사용으로 final두통을 줄일 수 있는 간단한 예입니다 .

public void setTest(String test) {
    test = test;
}

setter에서 'this'키워드를 잊어 버린 경우 설정하려는 변수가 설정되지 않습니다. 그러나 final매개 변수에 키워드 를 사용하면 컴파일 타임에 버그가 발생합니다.


65
btw 당신은 어쨌든 "변수 테스트에 대입이 효과가 없다"는 경고를 보게 될 것입니다
AvrDragon

12
@AvrDragon 그러나 경고도 무시할 수 있습니다. 따라서 컴파일 오류와 같이 최종 키워드를 사용하여 더 이상 진행하지 못하게하는 것이 항상 좋습니다.
Sumit Desai

10
@AvrDragon 개발 환경에 따라 다릅니다. 나쁜 습관을 개발하고 싶지 않다면 어쨌든 IDE를 사용하여 이와 같은 것을 잡아서는 안됩니다.
b1nary.atr0phy

25
@ b1naryatr0phy 실제로 IDE 팁뿐만 아니라 컴파일러 경고입니다
AvrDragon

8
@SumitDesai "그러나 경고도 무시할 수 있습니다. 따라서 컴파일 오류와 같이 더 이상 진행하지 못하게하는 것이 좋습니다. 최종 키워드를 사용하면 얻을 수 있습니다." 나는 당신의 요점을 취하지 만 이것은 많은 Java 개발자들이 동의하지 않을 것이라고 생각하는 매우 강력한 진술입니다. 컴파일러 경고에는 이유가 있으며 유능한 개발자는 그 의미를 고려하기 위해 오류를 '강제'할 필요가 없습니다.
스튜어트 Rossiter

127

예, 익명 클래스, 가독성 및 의도 선언을 제외하면 거의 가치가 없습니다. 그래도 그 세 가지는 가치가 없습니까?

final익명의 내부 클래스에서 변수를 사용하지 않는 한 개인적으로 로컬 변수 및 매개 변수 에 사용하지 않는 경향이 있지만 매개 변수 값 자체가 변경되지 않는다는 것을 분명히하려는 사람들의 요점을 확실히 알 수 있습니다 객체가 참조하는 경우 내용이 변경됨). 가독성을 높이는 사람들에게는 이것이 합리적이라고 생각합니다.

요점은 누군가가 실제로 주장한다면 더 중요 할 것 않았다 그러나 나는 그러한 주장을 본 기억이 없습니다 - 그것은하지 않는 방식으로 데이터를 일정하게 유지. final실제보다 더 많은 효과가 있다고 제안하는 많은 개발자가 있다고 제안하고 있습니까?

편집 : 나는이 모든 것을 Monty Python 참조와 요약해야합니다. 이 질문은 "로마인들이 우리를 위해 무엇을 해왔습니까?"


17
그러나 Krusty와 그의 덴마크어를 역설 하기 위해 최근에 우리를 위해 무엇을 습니까? =)
James Schek

유발. 재밌 네요! 칼날로 집행 되더라도 평화가 일어날 수있을 것 같아요!
gonzobrains

1
질문은 "무엇, 질문에 더 비슷한 것 같습니다 하지 않은 로마인들이 우리를 위해 행하신?", 더 최종 키워드가 무엇인지에 대한 비판 때문에 하지 않습니다.
NobleUplift

"최종이 실제보다 더 많은 효과를 제공 할 것을 제안하는 상당수의 개발자가 있다는 것을 제안하고 있습니까?" 나를 위해 그 입니다 주요 문제 : 난 강력하게 그것의 불변성 시행 생각 사용하는 개발자의 상당 부분을 의심 발신자 그렇지 않은 경우 전달 된 항목을. 물론, 코딩 표준이 개념적 오해 ( '유능한'개발자가 알고 있어야 함)를 '보호'해야하는지 아닌지에 대한 논쟁에 빠지게됩니다. 유형 질문)!
스튜어트 Rossiter

1
@SarthakMittal : 실제 값을 사용하지 않으면 값이 복사되지 않습니다.
Jon Skeet

76

나에게 당신은 하나의 사건에 대해 조금 설명하자 존 이미 언급 한 최종 사용을 :

메소드에서 익명의 내부 클래스를 작성하고 해당 클래스 내에 로컬 변수 (예 : 메소드 매개 변수)를 사용하는 경우 컴파일러는 매개 변수를 final로 설정하도록합니다.

public Iterator<Integer> createIntegerIterator(final int from, final int to)
{
    return new Iterator<Integer>(){
        int index = from;
        public Integer next()
        {
            return index++;
        }
        public boolean hasNext()
        {
            return index <= to;
        }
        // remove method omitted
    };
}

여기서 fromto매개 변수는 최종 클래스 여야 익명 클래스 내부에서 사용할 수 있습니다.

해당 요구 사항의 이유는 다음과 같습니다. 로컬 변수는 스택에 존재하므로 메서드가 실행되는 동안에 만 존재합니다. 그러나 익명 클래스 인스턴스는 메소드에서 리턴되므로 훨씬 오래 지속될 수 있습니다. 후속 메소드 호출에 스택이 필요하므로 스택을 보존 할 수 없습니다.

Java가 대신 로컬 변수의 사본 을 숨겨진 인스턴스 변수로 익명 클래스에 넣는 것입니다 (바이트 코드를 검사하면 볼 수 있음). 그러나 최종 클래스가 아닌 경우 익명 클래스와 다른 클래스가 변수를 변경하는 메소드를 볼 수 있습니다. 사본이 두 개가 아닌 변수가 하나만 있다는 착각을 유지하려면 최종 변수 여야합니다.


1
"최종이 아니라면 ..."에서 저를 잃어 버렸습니다.
hhafez 2009

1
로컬 변수가 있습니다. 메서드는 메소드 내에서 anon 클래스 인스턴스를 사용하고 from의 값을 변경하면 어떻게됩니까?-사람들은 변수가 하나만 표시되므로 메소드에 변경 사항이 표시 될 것으로 기대합니다. 이 혼동을 피하려면 최종적이어야합니다.
Michael Borgwardt

복사본을 만들지 않고 단순히 참조 된 객체에 대한 참조 일뿐입니다.
vickirk

1
@vickirk : 참조 유형의 경우 참조 사본을 만듭니다.
Michael Borgwardt

Btw에 이러한 변수를 참조하는 익명 클래스가 없다고 가정하면 finalHotSpot의 눈에 함수 매개 변수와 비 최종 함수 매개 변수 사이에 차이가 있는지 알고 있습니까?
Pacerier

25

나는 매개 변수에 항상 final을 사용합니다.

그렇게 많이 추가합니까? 실제로는 아닙니다.

끄겠습니까? 아니.

이유 : 사람들이 느슨한 코드를 작성하고 접근 자에서 멤버 변수를 설정하지 못한 3 가지 버그를 발견했습니다. 모든 버그를 찾기가 어려웠습니다.

향후 버전의 Java에서 이것이 기본값으로 사용되기를 바랍니다. 가치 / 참조에 의한 통과는 많은 주니어 프로그래머를 트립합니다.

한가지 더. 내 메소드에는 매개 변수 수가 적어 메소드 선언에 대한 추가 텍스트가 문제가되지 않습니다.


4
나는 이것도 제안하려고했는데, 그 최종 버전은 차후 버전에서 기본값이되고 "변경 가능"또는 더 나은 키워드를 지정해야한다고 제안했다. 여기에 관한 좋은 기사가 있습니다 : lpar.ath0.com/2008/08/26/java-annoyance-final-parameters
Jeff Axelrod

오랜 시간이 지났지 만 잡은 버그의 예를 들어 줄 수 있습니까?
user949300

답이 가장 많은 투표를 참조하십시오. 멤버 변수가 설정되지 않고 대신 매개 변수가 변경되는 좋은 예가 있습니다.
Fortyrunner

18

메소드 매개 변수에서 final을 사용하는 것은 호출자 측의 인수와 관련이 없습니다. 해당 메소드 내에서 변경되지 않는 것으로 표시하기위한 것입니다. 보다 기능적인 프로그래밍 스타일을 채택하려고 할 때 그 가치를 볼 수 있습니다.


2
정확히는 함수 인터페이스의 일부가 아니며 구현 만합니다. 자바 가 인터페이스 / 추상 메소드 선언의 매개 변수에 대해 허용하지만 혼란 스럽습니다 final.
Beni Cherniavsky-Paskin

8

개인적으로 나는 매개 변수 목록에 너무 많은 혼란을 더하기 때문에 메소드 매개 변수에 final을 사용하지 않습니다. Checkstyle과 같은 방법으로 메소드 매개 변수가 변경되지 않도록 강제하고 싶습니다.

로컬 변수의 경우 가능할 때마다 final을 사용하고 개인 프로젝트 설정에서 Eclipse가 자동으로 수행하도록합니다.

C / C ++ const와 같은 강력한 것을 확실히 원합니다.


IDE 및 도구 참조가 OP 전기 또는 주제에 적용되는지 확실하지 않습니다. 즉, "final"은 참조가 변경되거나 병합되지 않은 컴파일 타임 검사입니다. 또한 그러한 것들을 실제로 시행하려면 최종 참조의 하위 구성원에 대한 보호가 없다는 것에 대한 답변을 참조하십시오. 예를 들어 API를 빌드 할 때 IDE 또는 도구를 사용한다고해서 외부 사용자가 그러한 코드를 사용 / 확장하는 데 도움이되지는 않습니다.
Darrell Teague

4

Java는 인수 사본을 전달하므로 관련성 final이 다소 제한적 이라고 생각합니다 . 습관은 C ++ 시대에서 온 것으로 추측합니다. 여기서 참조 콘텐츠가 변경되는 것을 막을 수 const char const *있습니다. 나는 이런 종류의 것들이 개발자가 본질적으로 f ***처럼 어리 석고 자신이 타이핑하는 모든 캐릭터로부터 보호되어야한다고 생각합니다. 내가 겸손하게 말할 수 있듯이, 나는 final누군가가 내 메소드와 클래스를 재정의하지 않기를 원하지 않는 한 버그를 거의 작성 하지 않습니다. 어쩌면 나는 단지 구식 개발자 일 것입니다.


1

나는 매개 변수 목록에서 final을 사용하지 않으며 이전 응답자가 말한 것처럼 혼란을 더합니다. 또한 Eclipse에서 매개 변수 할당을 설정하여 오류를 생성 할 수 있으므로 매개 변수 목록에서 final을 사용하면 나에게 중복되는 것처럼 보입니다. 흥미롭게도 매개 변수 할당에 대해 Eclipse 설정을 활성화하면 오류가 발생 하여이 코드가 발생했습니다 (실제 코드가 아니라 흐름을 기억하는 방식입니다).

private String getString(String A, int i, String B, String C)
{
    if (i > 0)
        A += B;

    if (i > 100)
        A += C;

    return A;
}

악마의 옹호자 플레이를하는 것, 이것이 정확히 무엇입니까?


런타임 JVM과 IDE를 구별하기 위해 신중해야합니다. IDE가 변수를 다시 할당해서는 안되지만 실수로 의도했던 코드 결함과 같은 멤버 변수 병합을 막기 위해 IDE가 코드를 추가하지 않는 한 컴파일 된 바이트 코드가 서버에서 실행될 때 IDE가하는 것은 무의미합니다. 최종 키워드.
Darrell Teague

1

짧은 대답 : final약간 도움이되지만 ... 클라이언트 측에서 방어 프로그래밍을 대신 사용하십시오.

실제로 문제 final참조 가 변경되지 않고 강제로 참조 된 객체 멤버가 호출자에게 알려지지 않은 상태로 변경되도록 강제한다는 것 입니다. 따라서 이와 관련하여 모범 사례는 호출자 측의 방어 프로그래밍으로, 변경이 불가능한 API 또는 엉뚱한 API로 인해 위험에 처할 수있는 매우 불변의 인스턴스 또는 딥 사본을 생성하는 것입니다.


2
"final의 문제점은 참조 만 변경되지 않는다는 것입니다. " – 사실은 아닙니다. Java 자체는이를 방지합니다. 메소드에 전달 된 변수는 해당 메소드에 의해 참조가 변경 될 수 없습니다.
Madbreaks

게시하기 전에 조사하십시오 ... stackoverflow.com/questions/40480/…
Darrell Teague

간단히 말해서, 참조에 대한 참조가 변경 될 수 없다는 것이 사실이라면, 방어 적 복사, 불변성, 최종 키워드의 필요성 등에 대한 논의는 없을 것입니다.
Darrell Teague

당신은 나를 오해하고 있거나 잘못 알고 있습니다. 객체 참조를 메소드에 전달하고 해당 메소드가 객체를 다시 할당하면 메소드의 실행이 완료되면 호출자가 원래 참조를 그대로 유지합니다. Java는 엄격하게 가치를 전달합니다. 그리고 당신은 내가 아무 연구도하지 않았다고 주장하는 것을 뻔뻔스럽게 생각합니다.
Madbreaks

op가 final을 사용하는 이유를 물었 기 때문에 Downvoting, 당신은 단 하나의 잘못된 이유를주었습니다.
Madbreaks

0

매개 변수 선언에 final을 추가하는 또 다른 이유는 "추출 방법"리팩토링의 일부로 이름을 바꿔야하는 변수를 식별하는 데 도움이되기 때문입니다. 큰 메소드 리팩토링을 시작하기 전에 각 매개 변수에 final을 추가하면 계속하기 전에 해결해야 할 문제가 있는지 신속하게 알 수 있습니다.

그러나 리팩토링이 끝나면 일반적으로 불필요한 것으로 제거합니다.


-1

Michel의 게시물이 후속 조치입니다. 나는 내 자신이 그것을 설명하는 또 다른 예를 만들었다. 도움이 되길 바랍니다.

public static void main(String[] args){
    MyParam myParam = thisIsWhy(new MyObj());
    myParam.setArgNewName();

    System.out.println(myParam.showObjName());
}

public static MyParam thisIsWhy(final MyObj obj){
    MyParam myParam = new MyParam() {
        @Override
        public void setArgNewName() {
            obj.name = "afterSet";
        }

        @Override
        public String showObjName(){
            return obj.name;
        }
    };

    return myParam;
}

public static class MyObj{
    String name = "beforeSet";
    public MyObj() {
    }
}

public abstract static class MyParam{
    public abstract void setArgNewName();
    public abstract String showObjName();
}

메소드에서 위의 코드에서 thisIsWhy () , 우리가 실제로 할당하지 않은 [인수하여 MyObj OBJ] A와 실제 참조 하여 myParam에 있습니다. 대신 MyParam 내부의 메소드에서 [argument MyObj obj] 를 사용합니다.

그러나 우리는 방법 마친 후 thisIsWhy ()를 , 인수가 (객체)하여 MyObj은 여전히 존재한다?

main에서 볼 수 있기 때문에 showObjName () 메소드를 호출하고 obj 에 도달해야하기 때문에 있어야합니다 . MyParam은 메소드가 이미 리턴 된 경우에도 메소드 인수를 사용 / 도달합니다!

Java가 실제로 사본을 생성하는 방법 은 MyParam 객체 내부의 MyObj obj 인수에 대한 숨겨진 참조입니다 (그러나 MyParam의 공식 필드가 아니므로 볼 수 없습니다)

"showObjName"을 호출 할 때 해당 참조를 사용하여 해당 값을 가져옵니다.

그러나 인수를 final로 지정하지 않으면 상황이 발생하여 MyObj obj 인수에 새 메모리 (객체)를 다시 할당 할 수 있습니다 .

기술적으로 전혀 충돌이 없습니다! 우리가 그렇게 할 수 있다면 아래 상황이 있습니다.

  1. 이제 숨겨진 [MyObj obj]가 MyParam 객체에있는 [Memory A in heap]을 가리 킵니다.
  2. 또 다른 [MyObj obj]가 있는데, 이것은 [IsWhy] 메소드에 살고있는 [Memory B in heap]을 가리키는 인수입니다.

충돌은 없지만 "혼란!" 이들은 모두 "obj"인 동일한 "참조 이름"을 사용하기 때문 입니다.

이를 피하려면 프로그래머가 "실수하기 쉬운"코드를 수행하지 않도록 "최종"으로 설정하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.