보보보보
669
2018-01-17 08:04:05
5
2290

익명 객체와 final 의 사용에 대해


보통 익명객체 내에서는 변수들을 final로 사용해야하는 이유를 설명할 때


메서드 내에서 생성된 익명 객체는 메서드 실행이 끝나도 힙 메모리 영역에 존재해서 계속 사용할  수 있습니다.


그래서 나중에 익명객체를 쓸 때, 나중에 익명객체를 쓸 때, 로컬변수나 매개변수는 스택메모리에서 사라지기때문에 final로 써야한다 뭐 이런식으로 설명을 하는 것 같은데.


메소드 내에서 생성된 익명객체를 메소드 실행이 끝나도 사용한다는 게 무슨 말인지 모르겠네요.


예를 들어

class A{

    public void test(){

        List<String> a=new ArrayList<String>(){

                      int teacherName="Park";

            //teacherName="Kim"; 불가능

               }

    }

}

이렇게 있다고 칠 때,

a를 어떻게 메소드 실행 이후에도 사용한다는 건지 모르겠습니다.

a또한 하나의 변수로서 test()메소드 블록 안에서 선언 된 것이니, test()이후에는  a에 대해 접근 할 수 없는 것 아닌가요?

0
  • 답변 5

  • vernum
    972
    2018-01-17 08:40:19

    위 내용의 출처를 알 수 있나요?

  • asd
    16k
    2018-01-17 10:25:25

    이 글을 보고 할말이 2가지있습니다.

    1. 익명객체 내의 변수를 final로 선언해야한다는건 어디서 보신 내용인가요? 익명객체 '내'가 아니라 익명객체 '외' 아닌가요? '익명객체가 외부 변수를 참조할때 해당 외부변수가 final이어야한다.' 를 잘못 이해하신걸로 보입니다. 정말 저 내용이라면 어디서 나온얘기인지 궁금하네요.

    2. void가 아니라 return 이라면 어떨까요?

    public List<String>test(){
    return new ArrayList<String>(){
    int teacherName="Park";
    //teacherName="Kim"; 불가능
    };

    }

    이런 경우라면 메서드 내에서 생성한 익명객체를 외부에서도 사용할수있지않을까요?

  • 구구구구우
    1k
    2018-01-17 11:27:52

    LichKing 님의 말씀에 더 첨언해서 말씀드리면 

    익명클래스 에서 접근하려는 외부 클래스의 지역변수(외부 클래스의 멤버변수의 경우는 아닙니다. )의 경우는 final이어야 합니다 final 키워드를 쓰지 않으면 컴파일러가 잡아낸다는 거죠. java 7인가 8 인거 부터는 실질적으로 final이면  컴파일러가 알아서 판단합니다.(즉 final 키워드를 쓰지 않아도 실질적으로 final이면 그렇게 판단하고 컴파일 에러가 나지 않는다는 거죠)


    익명클래스내에서 외부클래스의 지역변수가 왜 final 이어야 하는지에 대한 이유는 말씀드리기가 상당히 복잡합니다. 몇가지 사전 지식이 필요하죠

    첫째, 변수 캡쳐와 클로저를 이해해야 합니다. 이것은 간단히 말하면 익명클래스에서 외부 클래스의 지역변수에 접근을 할수 있는 능력을 말하는 것이고, 더나아가 그렇게 접근한 외부클래스의 지역변수의 생명주기, 변경 가능성? 에 대한 이야기가 동반됩니다 


    둘째 자바에서의 캡쳔된 변수,  클로져 상황에서 해당 지역변수에 변경 가능성은 다른 언어(C#, 자바스크립트, C++)에 비해 다릅니다. 정확히 얘기하면  자바는 해당 지역변수에 대해 변경을 추적 할 수 가 없었습니다. 그래서 해당 지역변수가 변경될수 있음을 사전헤 차단하는 방법으로 클로저를 지원합니다. 즉 final 키워드를 명시적으로 표기 하겠끔 했죠,  앞서 말한것처럼 7?, 8? 부터는 실질적으로 final이면 해당 키워드를 안써도 되구요(final키워드를 안썼다고 변한다는건 아니니까요)


    세번째 위의 내용으로만 보면 부족하는 능력의 클로저를 제공하는 자바가 못미더워 보입니다. 하지만

    클로저 상황에서의 지역변수의 변경이 이루어짐이 필요한 상황은 드물며, 오히려 대부분 상황이 지역변수 변경이 이루어지며 안되는 상황이 더 많습니다. 그런 이유로 클로저를 제공하는 대부분의 언어들이 클로저를 소개할때 지역변수가 변경되지 않는 방식의 코드 작성방법을 소개합니다.


    다른 언어의 클로저를 살펴보시길 추천합니다. 다른 언에서 클로저는 익명클래스가 아닌 익명함수, 람다에서 발생하며 지역변수가 변경되는 예제는 대부분 for문의 지역변수가 익명 함수 또는 람다에서 어떤식으로 동작하는지에 대한 소개가 나오니 그것을 보시면 이해가 될겁니다.

  • 보보보보
    669
    2018-01-17 16:43:52

    제가 했던 내부클래스는 final만 써야한다는 말은 구구구구우 님의 말씀 처럼 외부의 변수도 내부에서는 final처럼 쓰이는 것 (java 최신?버젼에서부턴)그걸 얘기한 거였는데,

    생각보다 내용이 자세한 것이 었네요...

    이제 곧 복귀라 자세히 확인은 못하지만 이따 좀 더 자세히 확인하겠습니다!

  • asd
    16k
    2018-01-17 16:53:31

    자바는 메서드내의 지역변수에 대한 스레드안정성을 보장합니다. 지역변수를 내부 익명객체가 바꿀수있게(자바스크립트처럼) 만들어버리면 메서드내에서 스레드를 추가로 생성해서 지역변수의 값을 바꿀수도있게됩니다.

    그럼 결국 지역변수가 스레드안정성을 보장하지못하게되지요.

    그래서 인스턴스필드는 내부객체에서도 변경할 수 있지만 지역변수는 내부객체에서는 변경하지 못하게 만들었습니다.


  • 로그인을 하시면 답변을 등록할 수 있습니다.