[Java] final
final
final
클래스, 메소드, 변수에 선언할 수 있는 예약어입니다.
final의 의미(마지막) 그대로, 더이상 변경불가의 의미입니다.
final 클래스
다음과 같은 final 클래스가 있습니다.
public final class FinalClass{
}
이때 FinalClass를 상속받는 FinalChildClass가 아래와 같이 있다면
public class FinalChildClass extends FinalClass{
}
컴파일시 오류가 뜹니다.
이유는 final클래스는 상속받을 수 없기 때문입니다.
클래스를 상속받으면 오버라이딩을 통해서 변수나 메소드를 변경할 수 있겠죠.
변경 가능성을 원천 봉쇄하기위해 상속조차 막아버립니다.
final 메소드
다음과 같이 final메소드가 있는 클래스가 있습니다.
public class FinalMethodClass{
public final void printTeemo(){
System.out.println("teemo");
}
}
이 클래스를 상속받아 printTeemo()메소드를 오버라이딩하는 클래스가 아래와 같이 있다면
public class FinalMethodChildClass extends FinalMethodClass{
public void printTeemo(){
System.out.println("Super Teemo!");
}
}
컴파일시 에러가 납니다.
final메소드이기 때문입니다.
이렇게 final로 선언해놓으면 다른 개발자가 오버라이딩해 변경해 쓰기가 불가능할 것입니다.
final 변수(기본 자료형)
다음과 같이 final변수가 있습니다.
public class FinalVar{
//final int var1;
final int var2 = 1;
}
var1처럼 선언하면 에러가 납니다.
즉, 인스턴스 변수나 클래스 변수에 final을 붙이려면 생성과 동시에 초기화를 시켜줘야합니다.
하지만 매개변수나 지역변수는 생성할 때 초기화를 시킬 필요는 없습니다.
public class FinalVar{
final int var1 = 1;
public void method(final int parameter){
final int localVar;
}
}
즉, 위의 코드는 에러가 나지 않습니다.
하지만 다음은 에러가 납니다.
public class FinalVar{
final int var1 = 1;
public void method(final int parameter){
final int localVar;
localVar = 2;
localVar = 3;
parameter = 4;
}
}
에러가 나는 곳은 localVar = 3; 과 parameter = 4; 부분입니다.
둘다 이미 한번 초기화 된 곳인데 다시 값을 할당하려 하기 때문에 에러가 납니다.
final 변수(참조 자료형)
참조 자료형도 final로 선언되었으면 값을 두번 할당할 수 없습니다.
예로 다음과 같은 DTO클래스가 있다고 가정하겠습니다.
public class ChampionDTO {
public String name;
public int power;
public int defense;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ChampionDTO that = (ChampionDTO) o;
if (power != that.power) return false;
if (defense != that.defense) return false;
return name != null ? name.equals(that.name) : that.name == null;
}
@Override
public String toString() {
return "ChampionDTO{" +
"name='" + name + '\'' +
", power=" + power +
", defense=" + defense +
'}';
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + power;
result = 31 * result + defense;
return result;
}
public static void main(String[] ar){
}
}
그리고 final로 객체를 만듭니다.
public class FinalReferenceType {
final ChampionDTO dto = new ChampionDTO();
public static void main(String[] ar){
//dto = new ChampionDTO(); 이러면 에러!
FinalReferenceType ex = new FinalReferenceType();
ex.checkDTO();
// dto = ChampionDTO{name='null', power=0, defense=0}
// dto = ChampionDTO{name='teemo', power=0, defense=0}
}
public void checkDTO(){
System.out.println("dto = " + dto);
dto.name = "teemo";
System.out.println("dto = " + dto);
}
}
final 객체인 dto를 dto = new ChampionDTO();와 같이 재정의하면 에러가 납니다.
하지만 final 객체의 name값을 바꿨을 때는 아무 에러도 안나고 주석처럼 결과가 나오는 걸 볼 수 있습니다.
그 이유는 dto가 final객체이긴 해도 그 안에 선언된 name이란 변수는 final이 아니기 때문입니다.