programing

Java에서 "final" 키워드는 어떻게 작동합니까?(오브젝트를 변경할 수 있습니다.

javaba 2022. 7. 10. 11:22
반응형

Java에서 "final" 키워드는 어떻게 작동합니까?(오브젝트를 변경할 수 있습니다.

에서는 ""를 사용합니다.final값을 지정하는 변수를 포함하는 키워드는 변경되지 않습니다.그러나 클래스의 생성자/메서드에서 값을 변경할 수 있습니다. is음음음음음 the the the the again again again인 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말말효 ?과 ???

이것은 가장 좋아하는 면접 질문입니다.이 질문을 통해 인터뷰어는 컨스트럭터, 메서드, 클래스 변수(정적 변수) 및 인스턴스 변수에 대한 객체의 동작을 얼마나 잘 이해하고 있는지 알아보려고 합니다.

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' 메서드를 부여했습니다.

컨스트럭터 정보:컨스트럭터는 를 사용하여 오브젝트 작성당1회만 호출할 수 있습니다.new키워드를 지정합니다.을 사용하다 생성자가 여러 번 호출하도록 설계되지 않았기 때문입니다.

메서드에 대해서: 메서드는 원하는 횟수만큼 호출할 수 있으며(없어도), 컴파일러는 그것을 알고 있습니다.

시나리오 1

private final List foo;  // 1

foo인스턴스 변수입니다.작성 시Test 변수 클래스 오브젝트 "instance "를 선택합니다.foo , , , , , , , , , , , , , ,Test 하면. 만약 우리가 배정을 한다면foo컨스트럭터 내부에서 컴파일러는 컨스트럭터가 한 번만 호출된다는 것을 알고 있기 때문에 컨스트럭터 내부에서 할당하는 데 문제가 없습니다.

「」를 하면,foo번 될 수 있습니다.즉, 번 은, 「복수」에 되지 않습니다.final변수.따라서 컴파일러는 컨스트럭터가 좋은 선택이라고 판단합니다!최종 변수에는 한 번만 값을 할당할 수 있습니다.

시나리오 2

private static final List foo = new ArrayList();

foo이제 정적 변수가 되었습니다.의 인스턴스를 생성할 때Test ★★★★★★foo 오브젝트에는 복사되지 않습니다.foo, 이제foo는 각 오브젝트의 독립된 속성이 아닙니다.은 것은 of of of of of of of of of of 입니다.Test 근데 ㅇㅇㅇㅇㅇ.foo 될 수 있습니다.new하면, 으로 이 키워드는, 「이러다」를 합니다.Test 시 (Remember 여기기 ( )static foo는 모든 오브젝트에 복사되는 것이 아니라 여러 오브젝트 간에 공유됩니다.)

시나리오 3

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

★★Modification-2당신의 질문에서 나온 것입니다.경우 오브젝트는 합니다.foo가 불평하다. a a음 a a a a a a a a a a a a a a a a a a a a a a a a a a를 할당하려고 한다.new ArrayList()foo참조 변수.
규칙: 를 초기화하고 있는 경우final(이 경우는)ArrayList)

최종 클래스는 하위 클래스로 분류할 수 없습니다.
최종 메서드는 재정의할 수 없습니다.(이 메서드는 슈퍼클래스에 있습니다)
마지막 방법은 덮어쓸 수 있습니다. (문법으로 읽어주세요.)이 메서드는 서브클래스에 있습니다).

항상 초기화가 허용됩니다.final는 한번만 할 수 .컴파일러는 이 작업을 한 번만 수행할 수 있도록 합니다.

되어 있는 .final가 없습니다.final 말로 하자면:final는 참조 자체에 관한 것일 뿐 참조된 객체의 내용에 관한 것은 아닙니다.

Java는 객체 불변의 개념을 가지고 있지 않습니다.이것은 객체를 신중하게 설계함으로써 달성되는 것으로, 지극히 간단한 시도입니다.

Final 키워드에는 다음과 같은 다양한 사용 방법이 있습니다.

  • 최종 클래스는 하위 클래스로 분류할 수 없습니다.
  • 최종 메서드는 하위 클래스에서 재정의할 수 없습니다.
  • 최종 변수는 한 번만 초기화할 수 있습니다.

기타 용도:

  • 메서드 본문 내에 어나니머스 내부 클래스가 정의되어 있는 경우 해당 메서드의 범위에서 최종 선언된 모든 변수는 내부 클래스 내에서 액세스할 수 있습니다.

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

final키워드는 사용하는 내용에 따라 다음 두 가지 방법으로 해석할 수 있습니다.

값 유형:위해서ints,double등에서는 값이.s 、 등 、 이 、 이 등 、 록 、 s s s s s s s 。

참조 유형:오브젝트에 대한 참조는final참조가 변경되지 않도록 합니다.즉, 참조는 항상 같은 오브젝트를 참조합니다.오브젝트 내부의 값이 동일하게 유지된다는 보장은 전혀 없습니다.

★★★★★★★★★★★★★★★★.final List<Whatever> foo; 할 수 있습니다.foo는 항상 같은 목록참조하지만, 이 목록의 내용은 시간이 지남에 따라 변경될 수 있습니다.

당신이 만든다면foo해야 합니다.static은 다음과 같습니다.

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

private static final List foo;

static
{
   foo = new ArrayList();
}

인라인:

private static final List foo = new ArrayList();

는, 「어떻게」가 되는지가 .final가 어떻게 작용하는지, 하는지, 어떻게 작용하는지.static수식어가 기능합니다.

final수식자는 컨스트럭터에 대한 호출이 완료될 때까지 참조의 초기화를 강제합니다(즉, 컨스트럭터에서 초기화할 필요가 있습니다).

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

  • foostatic,foo = new ArrayList()는, 「 」보다 실행됩니다.static{}됩니다.
  • foostatic,foo = new ArrayList()됩니다.

final수정자는 사용자가 초기화하도록 강제하고 생성자에서 초기화해야 합니다.,도static컨스트럭터는 블록입니다. : 에속 、 mod mod mod mod mod 。static{}.

는, 「 」가 「 」라고 하는 입니다.static{}클래스가 로드될 때 해당 클래스의 오브젝트를 인스턴스화하기 전에 실행됩니다.되면 되지 않게 됩니다.foo클래스가 생성되었을 때.

★★★★★★★★★★★★★★★를 생각해 주세요.static{}Class서 '', '초기화'를static final클래스 어트리뷰트(인라인이 아닌 경우).

사이드 노트:

final 및 referencesmodifier에 합니다.

「 」를 선언했을 final " " " " " " " " " 가 됩니다.final 참조할 수는 있지만 개체 자체는 일정하지 않습니다.

「이행」을했을 때, 것.final를 선언한 Attribute 등):final List그 오브젝트는 할 수 .변경할 수 없습니다.List fooListListList사용하시는 내용이 변경되었을 경우에만 동일합니다.

이것은 매우 좋은 면접 질문입니다.때때로 그들은 당신에게 최종 물체와 불변의 물체의 차이가 무엇인지 물을 수도 있다.

1) 최종 객체를 언급하는 경우 참조는 변경할 수 없지만 상태(인스턴스 변수)는 변경할 수 있습니다.

2) 불변의 객체는 상태를 변경할 수 없지만 그 참조는 변경할 수 있는 객체이다.예:

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

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

3) 인스턴스 변수(비정적 필드)는 컨스트럭터를 호출할 때 초기화됩니다.따라서 생성자 내의 변수에 대한 값을 초기화할 수 있습니다.

4) "그러나 클래스의 생성자/메서드 값은 변경할 수 있습니다." -- 메서드 내에서는 변경할 수 없습니다.

5) 클래스 로드 중에 정적 변수를 초기화한다.따라서 컨스트럭터 내부에서는 초기화할 수 없습니다.이 작업은 컨스트럭터 이전이라도 수행해야 합니다.따라서 선언 자체 중에 정적 변수에 값을 할당해야 합니다.

final.default를 하기 위해 합니다.final키워드는 많은 컨텍스트에서 사용할 수 있습니다.파이널은 다음 중 하나입니다.

  1. 변수
  2. 방법
  3. 학급

final할 수 .final를 공백 변수라고 .final uninitialized variable variable variable 。final it 합니다.이치노 ★★final변수는 다음과 같습니다.static ,, ,, 기, 기에서 됩니다.static★★★★★★★★★★★★★★★★★★.

Java 최종 변수:

를 「」로 .final값은 변경할 수 없습니다.finalvariable(변수).

의 예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  

Java 최종 클래스:

만약 당신이 어떤 수업을 한다면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();  
      }  
  }  

Java 최종 방법:

메서드를 최종으로 하면 덮어쓸 수 없습니다.

의 예finalrun()는의 run 수 ) method (Honda의 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

다음과 같은 간단한 정의를 언급할 가치가 있습니다.

클래스/방법

또는 할 수 .final메서드를 서브클래스에 의해 덮어쓸 수 없음을 나타냅니다.

변수

a 번final변수가 초기화되었으며 항상 동일한 값을 포함합니다.

final기본적으로 대소문자에 따라 다른 항목(하위 클래스, 변수 "변수")에 의한 덮어쓰기/삭제를 방지합니다.

"A final variable can only be assigned once"

*Reflection* - "와~ 잠깐만 내 맥주들어줘"


동결final필드는 다음 두 가지 시나리오에서 발생합니다.

  • 생성자의 끝입니다.
  • 리플렉션이 필드 값을 설정하는 경우.(원하는 횟수만큼)

법을 어깁시다

public class HoldMyBeer 
{
    final int notSoFinal;
    
    public HoldMyBeer()
    {
       notSoFinal = 1;
    }

    static void holdIt(HoldMyBeer beer, int yetAnotherFinalValue) throws Exception
    {
       Class<HoldMyBeer> cl = HoldMyBeer.class;
       Field field = cl.getDeclaredField("notSoFinal");
       field.setAccessible(true);
       field.set(beer, yetAnotherFinalValue);
    }

    public static void main(String[] args) throws Exception 
    {
       HoldMyBeer beer = new HoldMyBeer();
       System.out.println(beer.notSoFinal);
       holdIt(beer, 50);
       System.out.println(beer.notSoFinal);
       holdIt(beer, 100);
       System.out.println(beer.notSoFinal);
       holdIt(beer, 666);
       System.out.println(beer.notSoFinal);
       holdIt(beer, 8888);
       System.out.println(beer.notSoFinal);
    }    
}

출력:

1
50
100
666
8888

"final" 필드에는 5개 "final" 값이 할당되어 있습니다(따옴표 참조).그리고 계속해서 다른 값을 할당할 수 있습니다.

왜일까요?반사는 척 노리스와 같기 때문에초기화된 최종 필드의 값을 바꾸고 싶다면 변경할 수 있습니다일부에서는 그 자신이 새로운 값을 스택에 밀어넣는 장본인이라는 의견도 있습니다.

Code:
   7: astore_1
  11: aload_1
  12: getfield                
  18: aload_1
  19: bipush        50        //wait what
  27: aload_1
  28: getfield                
  34: aload_1
  35: bipush        100       //come on...
  43: aload_1
  44: getfield                
  50: aload_1
  51: sipush        666      //...you were supposed to be final...
  60: aload_1
  61: getfield                
  67: aload_1
  68: sipush        8888     //ok i'm out whatever dude
  77: aload_1
  78: getfield                

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

public static final String hello = "Hello";

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

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

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

참고: final로 선언된 클래스는 확장 또는 상속할 수 없습니다(즉, 슈퍼 클래스의 하위 클래스는 존재할 수 없습니다).또한 final로 선언된 메서드는 서브클래스에 의해 덮어쓸 수 없습니다.

이 스레드에서는 final 키워드를 사용하는 메리트에 대해 설명합니다.

우선, 코드에서 foo를 초기화(즉, 처음 할당)하는 장소는 다음과 같습니다.

foo = new ArrayList();

foo는 개체(List 유형)이므로 값 유형(int 등)이 아닌 참조 유형입니다.따라서 List 요소가 저장된 메모리 위치(예: 0xA7D2A834)에 대한 참조가 유지됩니다.이런 선

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

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

foo = new ArrayList();

그러면 컴파일 오류가 발생합니다.


이제 static 키워드를 추가하면 어떻게 되는지 생각해 보겠습니다.

static 키워드가 없는 경우 클래스를 인스턴스화하는 각 개체에는 foo의 자체 복사본이 있습니다.따라서 생성자는 foo 변수의 빈 새 복사본에 값을 할당합니다. 이 복사본은 완벽하게 정상입니다.

단, static 키워드를 지정한 경우 클래스에 관련된 메모리에는 foo가1개만 존재합니다.2개 이상의 객체를 작성하면 컨스트럭터는 foo를 매번 재할당하려고 하고 최종 키워드를 위반합니다.

빨간색과 흰색의 두 개의 금고가 있다고 가정해 봅시다.이 금고에 두 명의 아이만 할당하면 금전은 교환할 수 없습니다.그래서 빨간색 또는 흰색 머니박스(최종)를 가지고 계시다면, 박스는 수정할 수 없지만, 박스에 돈을 넣을 수 있습니다.아무도 신경쓰지 않는다(수정-2).

모든 답을 읽어보세요.

로는 '하다'가 .finalKeyword 즉 메서드 인수에:사용될 수 있다.키워드는 메서드 인수에서 사용할 수 있습니다.

public void showCaseFinalArgumentVariable(final int someFinalInt){

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

}

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

스태틱 파이널로 할 때는 스태틱 초기화 블록으로 초기화해야 합니다.

    private static final List foo;

    static {
        foo = new ArrayList();
    }

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

final키워드 변수 한번만 초기화됨을 나타낸다.키워드는 변수를 한 번만 초기화할 수 있음을 나타냅니다.그래서 조건을 만족한다고 당신의 코드에 당신은 오직 최종의 한 초기화 공연을 하고 있다.코드에서는 조건이 충족되도록 최종 초기화를 한 번만 수행합니다.이 진술이 스테이트먼트는,다음의단독 초기화를 실행합니다의 외로운 초기화를 수행한다.foo.주의해 주세요습니다.final!=, 기준을 바꿀 수 없다는 것. 불변의!)불변의 경우 참조를 변경할 수 없습니다.

foo = new ArrayList();

언제선언할 때를 선포하다foo~하듯이로static final은 클래스를 적재 변수와 예시화(생성자에aka 전화)에 클래스가 로드될 때 초기화되어야 하며 초기화를 인스턴스화(컨스트럭터에 대한 호출이라고도 함)에 의존할 수 없습니다 변수는을 초기화하는 데 의존할 수 없초기화해야 합니다.foo이후 정적 필드는class.static 필드는 클래스의 인스턴스 없이 사용할 수 있어야 합니다의 인스턴스 없일 수 있어야 한다.보장은 없는 생성자 전 정적 필드를 사용하여 앞에 불려 갈까 하는 것이다.정적 필드를 사용하기 전에 생성자가 호출된다는 보장은 없습니다.

에서 static final를 쓰다Test가 로드되는 은, 「클래스」를.t에서는 의 는 foo되지 않았기 때문에 초기화되지 않았다는 것을 의미합니다.foo는 모든 에 대해 되어 있습니다.null에서는, 당신의 가 「」라고 하는 것을 할 수 NullPointerException항목을 목록에 추가하려고 할 때 사용합니다.

  1. 최종 변수는 비정적 변수이므로 생성자에서 초기화할 수 있습니다.단, 스태틱하게 하면 컨스트럭터가 스태틱하지 않기 때문에 컨스트럭터로 초기화할 수 없습니다.
  2. 리스트에의 추가는, 최종 리스트를 작성해도 정지하지 않습니다. final이치노해당 개체의 '상태'는 변경할 수 있지만 개체 자체는 변경할 수 없습니다.

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 variable은 나중에 값을 할당할 수 있지만(선언할 때 값을 할당할 필요는 없습니다). 단, 한 번만 할당할 수 있습니다.

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

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

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

Final methods 최종 메서드는 하위 클래스에서 재정의할 수 없습니다.

//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();
    }
}

저는 여기에 갱신된 상세 답변을 쓸까 생각 중입니다.

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

A final class다른 클래스는 최종 클래스를 확장할 수 없습니다.Java Run Time(JRE; Java 런타임)은 객체 참조가 최종 클래스 유형(예: 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. 방법들

A final method[ of any class ]는 해당 클래스를 확장하는 모든 자녀 클래스가 해당 최종 메서드를 덮어쓸 수 없음을 의미합니다.따라서 이 시나리오의 실행 시간 동작도 수업에서 언급한 이전 동작과 거의 동일합니다.

  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 캐시에 로드되어 메인 메모리에서 로드됩니다.퍼포먼스 향상이기도 합니다.

3가지 시나리오 에서 3가지 시나리오가 않은 final사용할 수 있는 장소에서 키워드를 사용하면 컴파일러의 최적화가 가능하기 때문에 걱정할 필요가 없습니다.컴파일러 최적화가 우리에게 가져다 주는 다른 많은 것들이 있습니다. :)

무엇보다도 옳다.또한 다른 사용자가 해당 클래스에서 하위 클래스를 만들지 않도록 하려면 해당 클래스를 최종 클래스로 선언하십시오.그러면 클래스 트리 계층의 리프 레벨이 되어 아무도 더 이상 확장할 수 없습니다.거대한 계층 구조를 피하는 것은 좋은 관행이다.

언급URL : https://stackoverflow.com/questions/15655012/how-does-the-final-keyword-in-java-work-i-can-still-modify-an-object

반응형