Java

[Java] final 키워드 그리고 effectively final

Tommy__Kim 2023. 6. 13. 11:52

final이란?

final은 클래스, 메서드, 변수에 사용될 수 있습니다.
final 키워드가 붙으면 특정한 무엇인가를 제한한다는 의미를 공통적으로 가지는데, 이 부분에 대해서 알아보도록 하겠습니다.

변수

변수에 final이 붙는다면 이 변수는 수정할 수 없다 라는 의미를 갖습니다.
primitive type의 경우 수정 자체가 불가능 하며, reference type 경우 가르키는 객체의 주소를 변경할 수 없습니다.
(객체의 내부 값은 영향을 받지 않습니다.)

public class Temporary {
    public static void main(String[] args) {
        final int int1 = 2;
        System.out.println("int1 = " + int1);
//         int1++;    // compile error

        final Person person;
        Person person1 = new Person();
        Person person2 = new Person();
        person = person1;
//         person = person2;    // compile error


    }
}

class Person {
    private String username;
    private int age;

    public Person() {
    }
}

메서드

메서드에 final이 붙으면 @Override가 불가능합니다.

class Parent {
    public int returnNotFinal() {
        return 10;
    }

    public final int returnFinal() {
        return 10;
    }
}

class Childeren extends Parent{

    @Override
    public int returnNotFinal() {
        return super.returnNotFinal();
    }
//    @Override        // compile error
//    public int returnFinal() {
//        return super.returnNotFinal();
//    }
}

클래스

클래스에 final이 붙으면 상속이 불가능합니다.

final class Parent {
    public int returnNotFinal() {
        return 10;
    }

}

// class Childeren extends Parent{    // compile error
// 
//    @Override
//    public int returnNotFinal() {
//        return super.returnNotFinal();
//    }
//}

Effectively final

변수에 final을 직접 명시하지는 않았지만, 변수의 값이 변경되지 않는다면, 그러한 변수를 Effectively final이라고 합니다.

간단한 예시에 앞서
Inner 클래스, 익명(anonymous)클래스 내부에서 외부의 변수를 접근 할 때에는 final 변수만 접근이 가능합니다.

public void returnNotFinal() {
        int number = 10;
        Runnable runnable = () -> System.out.println(number);
    }

위 예제에서 number에 final을 명시하지는 않았지만, number의 변경이 일어나지 않았습니다.
number는 effectively final로 인식되어 사용이 가능합니다.
그렇지만 다음과 같이 number의 값을 변경하는 순간 error가 발생합니다.

public void returnNotFinal() {
        int number = 10;
//        Runnable runnable = () -> System.out.println(number);    // compile error
        number++;
    }