불변(final)

불변 처리

final 키워드를 이용하면 대상에 대한 변경 또는 확장을 금지할 수 있다.

데모 1 : 메소드 내의 변수 불변 처리

public class FinalExample01 {
    public static void main(String[] args){
        final int a = 10;
        //a = 20;//error
        System.out.println("a = " + a);
    }
}

일반적인 변수의 경우 언제든지 원할 때 초기화가 가능하며, 초가화하면 기존의 값은 덮어씌여지게 된다. 하지만 값의 변경을 원하지 않는 경우가 발생할 수 있으며, 이 때 final키워드를 추가하여 재설정을 차단할 수 있다.

데모 2 : 클래스 내의 변수 불변 처리

class Member {
    private final String id;
    private String password;
    private String nickname;
    
    public Member(String id){
        this.id = id;
    }
    public Member(String id, String password, String nickname){
        this.id = id;
        this.setPassword(password);
        this.setNickname(nickname);
    }
    //final 항목에 대한 setter 생성 불가(setId)
    public void setPassword(String password){
        this.password = password;
    }
    public void setNickname(String nickname){
        this.nickname = nickname;
    }
    public String getId(){
        return this.id;
    }
    public String getPassword(){
        return this.password;
    }
    public String getNickname(){
        return this.nickname;
    }
}

public class FinalExample02 {
    public static void main(String[] args){
        Member member = new Member("admin", "1234", "운영자");
        member.setPassword("7777");
        member.setNickname("마스터");
        
        System.out.println("ID : " + member.getId());
        System.out.println("Password : " + member.getPassword());
        System.out.println("Nickname : " + member.getNickname());
    }
}

final 항목이 멤버 필드로 존재할 경우 반드시 생성자에서 초기화가 이루어져야 한다. 생성자에서 초기화가 이루어지지 않으면 값이 설정되지 않은 상태로 잠겨버리기 때문이며, 생성자가 여러 개일 경우에도 모든 생성자에서 초기화 구문이 작성되어야 한다.

또한 final 항목에 대한 setter 메소드는 허용되지 않는다. 단 한 번만 설정이 되기 때문에 setter메소드가 있을 필요가 없다.

데모 3 : static final 항목에 대한 불변 처리

class Calculator {
    static final double PI;
    static {
        PI = 3.141592;
    }
}

public class FinalExample03 {
    public static void main(String[] args){
        System.out.println(Calculator.PI);
    }
}

static 항목에 대한 final 처리는 조금 더 복잡하다. 그냥 값을 대입하면 상관없지만, 계산이 필요하다면 코드를 작성할 구문이 필요한데, 자바에서는 이를 위해 static 구문이 존재한다.

static {

}

static 구문에서는 static 항목에 대한 초기화가 가능하며, if, for, try~catch등 다양한 구문을 활용하여 초기화 할 수 있다. 초기화가 완료되고 난 이후의 항목은 불변 처리되어 변경이 이루어지지 않는다.

데모 4 : 메소드 불변 처리

class Phone {
    public final void call(String number){
        System.out.println(number+"로 전화를 겁니다");
    }
}

class IPhone extends Phone{
    //final 메소드는 재정의(override) 할 수 없다.
    //@Override
    //public void call(String number){ }
}

public class FinalExample04 {
    public static void main(String[] args){
        IPhone phone = new IPhone();
        phone.call();
    }
}

final을 이용한 메소드의 불변 처리는 상속(Inheritance)단원을 학습해야 이해할 수 있는 개념이므로 해당 문서를 살펴본 뒤에 보는 것이 좋다.

final 키워드를 통해 메소드를 불변 처리하면 재정의가 금지되어 일관된 메소드 이용을 강제할 수 있다.

데모 5 : 클래스 불변 처리

class Phone {}
final class IPhone extends Phone{}
//class IPhone11 extends IPhone{} //상속 불가

final을 이용한 클래스 불변 처리는 상속 단원을 학습해야 이해할 수 있는 개념으로 해당 문서를 살펴본 뒤에 보는 것이 좋다.

final 키워드가 클래스에 작성될 경우 클래스 자체가 불변 상태가 되어 상속이 이루어지지 않는다.

Last updated