Java의 "최종"키워드는 어떻게 작동합니까? (여전히 개체를 수정할 수 있습니다.)


480

Java에서는 final변수와 함께 키워드를 사용하여 값을 변경하지 않도록 지정합니다. 그러나 클래스의 생성자 / 메소드에서 값을 변경할 수 있음을 알았습니다. 변수가 static그렇다면 컴파일 오류입니다.

코드는 다음과 같습니다.

import java.util.ArrayList;
import java.util.List;

class Test {
  private final List foo;

  public Test()
  {
      foo = new ArrayList();
      foo.add("foo"); // Modification-1
  }
  public static void main(String[] args) 
  {
      Test t = new Test();
      t.foo.add("bar"); // Modification-2
      System.out.println("print - " + t.foo);
  }
}

위의 코드는 정상적으로 작동하며 오류가 없습니다.

이제 변수를 static다음 과 같이 변경하십시오 .

private static final List foo;

이제 컴파일 오류입니다. 이것이 final실제로 어떻게 작동합니까?


foo가 보이지 않기 때문에 어떻게 컴파일 할 수 있습니까?
Björn Hallström

5
사실이 아닌 @therealprashant. 전용 정적 변수는 유효하며 정의 된 클래스 내부의 정적 메서드에서 액세스 할 수 있습니다. 정적 변수는 변수가 한 번 존재하며 클래스의 인스턴스에 바인딩되지 않았 음을 의미합니다.
mbdavis

3
@mbdavis 오 예! 감사합니다. 그러나 여전히 나는 나와 같은 생각을하는 사람들을 돕기 위해 주석을 삭제하지 않으며 귀하의 의견은 그들이 올바른 방향으로 생각하게합니다.
therealprashant

@therealprashant 괜찮아 걱정하지 마세요!
mbdavis

답변:


518

항상 변수 를 초기화final수 있습니다. 컴파일러는 한 번만 수행 할 수 있도록합니다.

final변수에 저장된 객체에서 메소드를 호출하는 것은의 의미와 관련이 없습니다 final. 다시 말해 final, 참조 자체에 관한 것이며 참조 된 객체의 내용에 관한 것이 아닙니다.

Java에는 객체 불변성 개념이 없습니다. 이것은 신중하게 객체를 디자인함으로써 달성되며 사소한 노력과는 거리가 멀다.


12
t.foo = new ArrayList ()를 시도하십시오. 메인 메소드에서 컴파일 오류가 발생합니다 ... 참조 foo는 ArrayList의 하나의 최종 객체에만
바인딩

50
흠. 그것은 가치가 아닌 참조에 관한 것입니다. 감사!
GS

2
질문이 있습니다. 내가 "최종"이라고 주장하는 사람은 변수를 스택에 저장합니다. 이 올바른지? 나는 모든 곳을 검색 했으며이 주장을 승인하거나 승인 할 수없는 참조를 찾을 수 없었습니다. Java 및 Android 설명서를 모두 검색했습니다. "자바 메모리 모델"도 검색했습니다. 어쩌면 C / C ++에서는 이런 식으로 작동하지만 Java에서는 이런 식으로 작동하지 않는다고 생각합니다. 제가 맞습니까?
안드로이드 개발자

4
@androiddeveloper Java의 어떤 것도 스택 / 힙 배치를 명시 적으로 제어 할 수 없습니다. 보다 구체적으로, HotSpot JIT 컴파일러에 의해 결정된 스택 배치는 이스케이프 분석의 대상이되며 이는 변수가 아닌지 확인하는 것보다 훨씬 더 복잡합니다 final. 가변 객체도 스택 할당 할 수 있습니다. final필드 이스케이프 분석에 도움이 수 있지만 이는 매우 간접적 인 경로입니다. 또한 효과적으로 최종 변수는 final소스 코드에 표시된 것과 동일한 처리를 합니다.
Marko Topolnik

5
final클래스 파일에 있으며 런타임 최적화에 중요한 의미를 갖습니다. JLS에는 객체 필드의 일관성에 대한 강력한 보증이 있기 때문에 비용 이 발생할 수도 있습니다 final. 예를 들어 ARM 프로세서는 final필드 가있는 클래스의 각 생성자 끝에 명시 적 메모리 장벽 명령어를 사용해야 합니다. 그러나 다른 프로세서에서는 필요하지 않습니다.
Marko Topolnik

574

이것은 가장 좋아하는 인터뷰 질문 입니다. 이 질문을 통해 면접관은 생성자, 메서드, 클래스 변수 (정적 변수) 및 인스턴스 변수와 관련하여 개체의 동작을 얼마나 잘 이해하는지 알아 봅니다.

import java.util.ArrayList;
import java.util.List;

class Test {
    private final List foo;

    public Test() {
        foo = new ArrayList();
        foo.add("foo"); // Modification-1
    }

    public void setFoo(List foo) {
       //this.foo = foo; Results in compile time error.
    }
}

위의 경우 'Test'에 대한 생성자를 정의하고 'setFoo'메소드를 제공했습니다.

생성자 정보 : 생성자는 키워드 를 사용하여 객체 생성 당 번만 호출 할 수 있습니다 new. 생성자는 그렇게 설계되지 않았으므로 생성자를 여러 번 호출 할 수 없습니다.

메소드 정보 : 메소드는 원하는 횟수만큼 호출 할 수 있으며 (아직도) 컴파일러가 알고 있습니다.

시나리오 1

private final List foo;  // 1

foo이다 인스턴스 변수. Test클래스 객체를 만들면 인스턴스 변수 fooTest클래스 의 객체 내부에 복사됩니다 . foo생성자 내부에 할당 하면 컴파일러는 생성자가 한 번만 호출된다는 것을 알고 있으므로 생성자 내부에 할당하는 데 아무런 문제가 없습니다. 메서드 내부에

할당 foo하면 컴파일러는 메서드를 여러 번 호출 할 수 있다는 것을 알고 있습니다. 즉, 값을 여러 번 변경해야하므로 final변수에 사용할 수 없습니다 . 그래서 컴파일러는 생성자가 좋은 선택이라고 결정합니다! 최종 변수에는 한 번만 값을 지정할 수 있습니다.

시나리오 2

private static final List foo = new ArrayList();

foo이제 정적 변수입니다. Test클래스 의 인스턴스를 만들면 정적 foo이므로 객체에 복사되지 않습니다 foo. 이제는 foo각 객체의 독립적 인 속성이 아닙니다. 이것은 Test클래스 의 속성입니다 . 그러나 foo여러 객체와 new키워드를 사용하여 생성 된 모든 객체가 Test여러 객체 생성시 값을 변경하는 생성자를 호출하는 경우 ( static foo모든 객체에 복사되지는 않지만 여러 객체간에 공유 됨) .)

시나리오 3

t.foo.add("bar"); // Modification-2

Modification-2의 질문에서입니다. 위의 경우 첫 번째 참조 객체를 변경하지 않고 foo허용되는 내용을 추가합니다 . 참조 변수에 a new ArrayList()를 할당하려고하면 컴파일러가 불평 foo합니다.
규칙final 변수를 초기화 한 경우 다른 개체를 참조하도록 변수를 변경할 수 없습니다. (이 경우 ArrayList)

최종 클래스는 서브 클래 싱 될 수 없습니다.
최종 메소드는 재정의 될 수 없습니다. (이 메소드는 수퍼 클래스에 있습니다. )
final 메소드는 재정의 할 수 있습니다. 문법적으로 읽습니다.이 방법은 서브 클래스에 있습니다.


1
분명해 지려면 시나리오 2 에서 테스트 클래스에 설정되어 있고 여러 테스트 인스턴스가 작성된 foo경우 최종 지정에도 불구하고 여러 번 설정 될 것이라고 말하는가 foo?
Rawr

시나리오 2의 마지막 줄을 이해하지 않았 : 하지만 foo할 수 있습니다 .. 여러 개체를). 그때, 한 번에 여러 개체를 만드는 경우 최종 변수를 초기화하는 것은 실행에 달려있다하는 객체, 그 의미인가?
Saumya Suhagiya

1
시나리오 3에 대해 생각할 수있는 유용한 방법 은 ArrayList가 final참조하는 메모리 주소에 할당 foo하는 것입니다. final첫 번째 요소 foo(또는 해당 문제의 요소)가 참조하는 메모리 주소를 할당하지 않았습니다 . 따라서 변경할 수는 없지만 변경할 foo수 있습니다 foo[0].
Pinkerton

의 때문에 약자로 @Rawr는, 시나리오 2는 컴파일 타임 오류가 발생합니다 foo = new ArrayList();- foo우리는 같은 클래스 안에이기 때문에 정적 변수를 참조.
flow2k

Java를 배우는 C ++ 개발자입니다. final변수를 constC ++ 의 키워드 와 동일 하게 생각하는 것이 안전 합니까?
Doug Barbieri

213

최종 키워드에는 여러 가지 방법이 있습니다.

  • 최종 클래스 는 서브 클래 싱 될 수 없습니다.
  • 서브 클래스로 최종 메소드 를 대체 할 수 없습니다.
  • 최종 변수 는 한 번만 초기화 할 수 있습니다

다른 사용법 :

  • 익명의 내부 클래스가 메소드 본문 내에 정의되면 해당 메소드의 범위에서 final로 선언 된 모든 변수는 내부 클래스에서 액세스 할 수 있습니다.

정적 클래스 변수는 JVM 시작부터 존재하며 클래스에서 초기화해야합니다. 이렇게하면 오류 메시지가 나타나지 않습니다.


24
이것은 지금까지 내가 가장 좋아하는 대답입니다. 간단하고 간단하게 Java에 대한 온라인 문서에서 읽을 것으로 예상됩니다.
RAnders00

정적 변수에서 원하는만큼 초기화 할 수 있습니까?
jorge saraiva

1
@jorgesaraiva 예, 정적 변수는 상수가 아닙니다.
czupe

1
@jorgesaraiva 필드 를 원하는 만큼 ( 초기화 하지 않는 한 ) 할당 할 수 있습니다 . 할당초기화 의 차이점에 대해서는 이 위키 를 참조하십시오 . staticfinal

56

그만큼 final이에 사용되는 어떤 키워드에 따라 두 가지 방법으로 해석 될 수있다 :

값 유형 : 대한 int의,double 값이 변경되지 수의 등이 보장됩니다

참조 유형 : 객체에 대한 참조 final참조가 가 변경되지 항상 동일한 객체를 참조합니다. 객체 내부의 값이 동일하게 유지되는 것을 보장하지 않습니다.

같은 final List<Whatever> foo;보장 foo항상을 의미 같은 목록,하지만 내용 말했다 목록은 시간이 지남에 따라 변경 될 수 있습니다.


23

당신이 만드는 경우 foo 정적을, 다음과 같은 예처럼 (당신이 그것을 정의하거나 인라인) 클래스 생성자에서 초기화해야합니다.

클래스 생성자 (인스턴스 아님) :

private static final List foo;

static
{
   foo = new ArrayList();
}

인라인 :

private static final List foo = new ArrayList();

여기서 문제는 final수정자가 작동하는 방식이 아니라static 수정자가 작동하는 방식입니다.

final수정자는 시간 (생성자에서 초기화해야 즉) 생성자의 완료에 대한 호출을 참조의 초기화를 실행합니다.

인라인으로 속성을 초기화하면 생성자에 대해 정의한 코드가 실행되기 전에 속성이 초기화되므로 다음과 같은 결과가 나타납니다.

  • 경우 foo이며 static, foo = new ArrayList()전과 실행됩니다 static{}당신이 당신의 클래스에 정의한 생성자가 실행
  • 경우 foo없는 static, foo = new ArrayList()생성자가 실행되기 전에 실행됩니다

속성을 인라인으로 final초기화 하지 않으면 수정자는 속성 을 초기화하고 생성자에서이를 초기화해야합니다. 당신은 또한이 있으면 static수정을 생성자는이 클래스의 초기화 블록의 속성을 초기화해야합니다 :static{} .

코드에서 발생하는 오류 static{}는 해당 클래스의 객체를 인스턴스화하기 전에 클래스가로드 될 때 실행 되는 사실 에서 발생합니다. 따라서 foo클래스를 만들 때 초기화되지 않았습니다 .

static{}블록을 유형의 객체에 대한 생성자로 생각하십시오 Class. 이것은 당신이 당신의 초기화를 수행 해야하는 곳입니다static final 클래스 속성을 합니다 (인라인으로 수행되지 않은 경우).

사이드 노트 :

그만큼 final수정 보증한다은에서 const - 다움 만 원시 형과 참조하십시오.

final객체 를 선언 하면 얻을 수있는 것은 final 참조입니다 해당 객체에 이지만 객체 자체는 일정하지 않습니다.

무엇 선언 할 때 당신이 정말로 달성하고 final당신이 (등 특정 목적을 위해 객체를 선언하면 속성은, 그 것이다 final List당신은 변경할 수 없습니다 : 당신이 선언 한 것을)와 객체가 그 목적을 위해 사용됩니다에만 있다는 것을, List foo에 다른 항목 List이지만 List항목을 추가 / 제거하여 여전히 내용을 변경할 수 있습니다 ( List사용중인 내용은 내용이 변경된 경우에만 동일 함).


8

이것은 매우 좋은 인터뷰 질문입니다. 때로는 최종 객체와 불변 객체의 차이점이 무엇인지 묻기도합니다.

1) 누군가가 최종 객체를 언급하면 ​​참조를 변경할 수 없지만 상태 (인스턴스 변수)는 변경할 수 있음을 의미합니다.

2) 불변 개체는 상태를 변경할 수 없지만 참조를 변경할 수있는 개체입니다 . 전의:

    String x = new String("abc"); 
    x = "BCG";

ref 변수 x는 다른 문자열을 가리 키도록 변경할 수 있지만 "abc"값은 변경할 수 없습니다.

3) 생성자 호출시 인스턴스 변수 (비 정적 필드)가 초기화됩니다. 따라서 생성자 내에서 변수 값을 초기화 할 수 있습니다.

4) "하지만 클래스의 생성자 / 메소드에서 값을 변경할 수 있습니다." -메소드 내에서 변경할 수 없습니다.

5) 정적 변수는 클래스 로딩 중에 초기화됩니다. 따라서 생성자 내부에서 초기화 할 수 없으므로 생성자 이전에도 수행해야합니다. 따라서 선언 하는 동안 정적 변수에 값을 할당해야 합니다.


7

finaljava 의 키워드는 사용자를 제한하는 데 사용됩니다. java final키워드는 많은 상황에서 사용될 수 있습니다. 최종은 다음과 같습니다.

  1. 변하기 쉬운
  2. 방법
  3. 수업

final키워드는 변수와 함께 적용 할 수있는 final, 값이없는 변수를 빈이라고 final변수 또는 초기화되지 않은 final변수입니다. 생성자에서만 초기화 할 수 있습니다. 빈 final변수는 블록에서만 static초기화 될 수 있습니다 static.

자바 최종 변수 :

당신이 어떤 변수로 한 경우 final, 당신은 값을 변경할 수final(그것은 일정하게 될 것입니다) 변수를.

final변수의 예

최종 변수 속도 제한이 있습니다.이 변수의 값을 변경할 것입니다. 그러나 일단 값이 할당 된 최종 변수는 절대 변경할 수 없으므로 변경할 수 없습니다.

class Bike9{  
    final int speedlimit=90;//final variable  
    void run(){  
        speedlimit=400;  // this will make error
    }  

    public static void main(String args[]){  
    Bike9 obj=new  Bike9();  
    obj.run();  
    }  
}//end of class  

자바 최종 클래스 :

클래스를로 만들면 확장final수 없습니다 .

최종 수업의 예

final class Bike{}  

class Honda1 extends Bike{    //cannot inherit from final Bike,this will make error
  void run(){
      System.out.println("running safely with 100kmph");
   }  

  public static void main(String args[]){  
      Honda1 honda= new Honda();  
      honda.run();  
      }  
  }  

자바 최종 방법 :

어떤 방법을 최종으로 만들면 무시할 수 없습니다 .

finalHonda의 run () 메소드 예제는 Bike의 run ()을 대체 할 수 없습니다.

class Bike{  
  final void run(){System.out.println("running");}  
}  

class Honda extends Bike{  
   void run(){System.out.println("running safely with 100kmph");}  

   public static void main(String args[]){  
   Honda honda= new Honda();  
   honda.run();  
   }  
}  

http://www.javatpoint.com/final-keyword 에서 공유


7

몇 가지 간단한 정의를 언급 할 가치가 있습니다.

수업 / 방법

final서브 클래스로 메소드를 대체 할 수 없음을 나타 내기 위해 클래스 메소드의 일부 또는 전부를로 선언 할 수 있습니다 .

변수

한 번 final변수가 초기화 된, 항상 같은 값을 포함합니다.

final 기본적으로 경우에 따라 무엇이든 (서브 클래스, 변수 "reassign") 덮어 쓰기 / 감추기를 피하십시오.


1
변수에 대한 최종 정의가 약간 짧다고 생각합니다. "Java에서 final 키워드를 기본 데이터 유형 (int, float 등)의 변수와 함께 사용하는 경우 변수 값을 변경할 수 없지만 기본이 아닌 변수와 함께 final을 사용하는 경우 (기본이 아닌 변수에 유의하십시오) 기본 객체가 아닌 변수에 대한 final은 다른 객체를 참조하도록 변경할 수 없음을 의미합니다. " geeksforgeeks.org/g-fact-48
ceyun

특히 기본 및 비 기본 사례로 언급 할 때도 유효합니다. Tks.
ivanleoncz

4

finalJava에서 사용자를 제한하기 위해 예약 된 키워드이며 멤버 변수, 메소드, 클래스 및 로컬 변수에 적용 할 수 있습니다. 최종 변수는 종종 static키워드를 Java로 선언하여 상수로 취급합니다. 예를 들면 다음과 같습니다.

public static final String hello = "Hello";

final변수 선언과 함께 키워드를 사용하면 해당 변수 안에 저장된 값을 나중에 변경할 수 없습니다.

예를 들면 다음과 같습니다.

public class ClassDemo {
  private final int var1 = 3;
  public ClassDemo() {
    ...
  }
}

참고 : final로 선언 된 클래스는 확장 또는 상속 될 수 없습니다 (즉, 수퍼 클래스의 하위 클래스가있을 수 없음). final로 선언 된 메소드는 서브 클래스로 대체 할 수 없습니다.

키워드에서는 최종 키워드를 사용할 때의 이점에 대해 설명합니다 .


2
the value stored inside that variable cannot be changed latter부분적으로 사실입니다. 기본 데이터 유형에만 해당됩니다. finalarraylist와 같이 객체를 만든 경우 해당 값은 변경할 수 있지만 참조는 변경할 수 없습니다. 감사합니다!
GS

3

빨간색과 흰색의 돈 상자가 두 개 있다고 가정합니다. 이 돈 상자에는 두 명의 자녀 만 할당하고 상자를 서로 교환 할 수 없습니다. 따라서 빨간색 또는 흰색 머니 박스 (최종)가 있으면 상자를 수정할 수 없지만 상자에 돈을 넣을 수 있습니다.


2

모든 답을 읽으십시오.

final키워드를 메소드 인수에서 사용할 수있는 또 다른 사용자 사례가 있습니다.

public void showCaseFinalArgumentVariable(final int someFinalInt){

   someFinalInt = 9; // won't compile as the argument is final

}

변경할 수없는 변수에 사용할 수 있습니다.


1

정적 최종으로 만들면 정적 초기화 블록에서 초기화되어야합니다.

    private static final List foo;

    static {
        foo = new ArrayList();
    }

    public Test()
    {
//      foo = new ArrayList();
        foo.add("foo"); // Modification-1
    }

1

final키워드는 변수가 한 번만 초기화 할 수 있음을 나타냅니다. 코드에서 final의 한 가지 초기화 만 수행하므로 용어가 충족됩니다. 이 문은의 단독 초기화를 수행합니다 foo. 유의 final! = 불변 그것은 유일한 수단 기준은 변경할 수있다.

foo = new ArrayList();

당신이 선언 할 때 foo같은 static final변수가 클래스가로드 될 때 초기화해야합니다 및 인스턴스에 의존 할 수 초기화 (일명 생성자에 문의)foo 정적 필드는 클래스의 인스턴스없이 사용할 수 있어야하기 때문이다. 정적 필드를 사용하기 전에 생성자가 호출되었다는 보장은 없습니다.

static final시나리오에서 메소드를 실행할 때이 시점에서 Test인스턴스화하기 전에 클래스가로드 되면 초기화되지 않았 음 tfoo의미하는 인스턴스화가 없으므로 foo모든 오브젝트에 대해 기본값으로 설정됩니다 null. 이 시점 NullPointerException에서 항목을 목록에 추가하려고하면 코드에서 a가 발생 한다고 가정합니다 .


1

우선, 코드에서 초기화 (즉, 처음으로 할당)하는 foo 위치는 다음과 같습니다.

foo = new ArrayList();

foo는 List 유형의 객체이므로 int와 같은 유형이 아닌 참조 유형 입니다. 따라서 List 요소가 저장된 메모리 위치 (예 : 0xA7D2A834)에 대한 참조를 보유합니다. 이 같은 라인

foo.add("foo"); // Modification-1

foo 값을 변경하지 마십시오 (다시 말해 메모리 위치에 대한 참조 일뿐). 대신, 참조 된 메모리 위치에 요소를 추가하기 만합니다. 최종 키워드 를 위반하려면 다음과 같이 foo를 다시 할당해야합니다.

foo = new ArrayList();

것이다 당신에게 컴파일 오류를 제공합니다.


이제 그 방법으로 정적 키워드 를 추가 할 때 어떤 일이 발생하는지 생각해보십시오 .

static 키워드가 없으면 클래스를 인스턴스화하는 각 객체에는 자체 foo 사본이 있습니다. 따라서 생성자는 빈 foo 변수의 빈 복사본에 값을 할당합니다.

그러나 static 키워드가 있으면 클래스와 연관된 메모리에 하나의 foo 만 존재합니다. 두 개 이상의 객체를 만들려면 생성자가 최종 키워드를 위반하여 매번 하나의 foo를 다시 할당하려고 시도 합니다.


1
  1. 최종 변수는 비정 적이므로 생성자에서 초기화 할 수 있습니다. 그러나 정적 인 경우 생성자가 정적이 아니기 때문에 생성자로 초기화 할 수 없습니다.
  2. 목록에 추가하는 것은 목록을 최종적으로 만들어 중단 될 것으로 예상되지 않습니다. final참조를 특정 객체에 바인딩합니다. 해당 객체의 '상태'는 자유롭게 변경할 수 있지만 객체 자체는 변경할 수 없습니다.

1

다음은 final이 사용되는 다른 컨텍스트입니다.

최종 변수 최종 변수는 한 번만 지정할 수 있습니다. 변수가 참조 인 경우 다른 개체를 참조하기 위해 변수를 리 바인드 할 수 없습니다.

class Main {
   public static void main(String args[]){
      final int i = 20;
      i = 30; //Compiler Error:cannot assign a value to final variable i twice
   }
}

최종 변수는 나중에 값을 지정할 수 있지만 (선언 될 때 값을 할당 할 필요는 없음) 한 번만 가능합니다.

최종 클래스 최종 클래스는 확장 할 수 없습니다 (상 속됨)

final class Base { }
class Derived extends Base { } //Compiler Error:cannot inherit from final Base

public class Main {
   public static void main(String args[]) {
   }
}

최종 메소드 최종 메소드는 서브 클래스로 대체 할 수 없습니다.

//Error in following program as we are trying to override a final method.
class Base {
  public final void show() {
       System.out.println("Base::show() called");
    }
}     
class Derived extends Base {
    public void show() {  //Compiler Error: show() in Derived cannot override
       System.out.println("Derived::show() called");
    }
}     
public class Main {
    public static void main(String[] args) {
        Base b = new Derived();;
        b.show();
    }
}

1

나는 여기에 업데이트되고 깊이있는 답변을 쓰는 ​​것을 생각했습니다.

final 키워드는 여러 곳에서 사용할 수 있습니다.

  1. 클래스

A final class는 다른 클래스가 해당 최종 클래스를 확장 할 수 없음을 의미합니다 . Java 런타임 ( JRE )은 객체 참조가 최종 클래스의 유형 (예 : F)임을 알고 있으면 해당 참조의 값은 F 유형 만 될 수 있다는 것을 알고 있습니다.

전의:

F myF;
myF = new F();    //ok
myF = someOther;  //someOther cannot be in type of a child class of F.
                  //because F cannot be extended.

따라서 해당 객체의 메소드 를 실행할 때 가상 테이블을 사용하여 런타임에 해당 메소드 를 분석 할 필요가 없습니다 . 즉, 런타임 다형성을 적용 할 수 없습니다. 따라서 런타임은 그것에 대해 신경 쓰지 않습니다. 즉, 처리 시간이 절약되어 성능이 향상됩니다.

  1. 행동 양식

final method클래스를 확장 하위 클래스가 임의의 클래스 수단의 무시할 수없는 그 마지막 방법 (들). 따라서이 시나리오의 런타임 동작은 클래스에서 언급 한 이전 동작과 상당히 동일합니다.

  1. 필드, 지역 변수, 메소드 매개 변수

위에서 위와 같은 종류를 지정한 경우 final값이 이미 확정되었으므로 값을 변경할 수 없습니다 .

전의:

필드의 경우 로컬 매개 변수

final FinalClass fc = someFC; //need to assign straight away. otherwise compile error.
final FinalClass fc; //compile error, need assignment (initialization inside a constructor Ok, constructor can be called only once)
final FinalClass fc = new FinalClass(); //ok
fc = someOtherFC; //compile error
fc.someMethod(); //no problem
someOtherFC.someMethod(); //no problem

메소드 파라미터

void someMethod(final String s){
    s = someOtherString; //compile error
}

이는 단순히 final기준값을 변경할 수 없음을 의미합니다 . 즉, 하나의 초기화 만 허용됩니다. 이 시나리오에서 런타임시 JRE 는 값을 변경할 수 없음을 알고 있으므로 최종 참조의 모든 최종 값을 L1 캐시에로드합니다 . 그것은 때문에 필요하지 않습니다다시로드 에서 또 다시 메인 메모리 . 그렇지 않으면 L2 캐시에로드되고 기본 메모리에서 시간에 따라로드됩니다. 성능 향상이기도합니다.

따라서 위의 세 가지 시나리오에서 final사용할 수있는 위치에 키워드를 지정 하지 않은 경우 걱정할 필요가 없습니다. 컴파일러 최적화 가 그렇게 할 것입니다. 컴파일러 최적화가 우리를 위해하는 다른 많은 것들도 있습니다. :)


0

무엇보다도 정확합니다. 또한 다른 사람들이 클래스에서 하위 클래스를 만들지 않게하려면 클래스를 final로 선언하십시오. 그러면 아무도 더 이상 확장 할 수없는 클래스 트리 계층의 리프 수준이됩니다. 클래스의 거대한 계층 구조를 피하는 것이 좋습니다.

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