Java에서 final이란 예약어가 있다. 이건 영어로 해석해보면 최종의, 최후의 란 뜻으로 말그대로 클래스에 쓰이면 상속을 불가능하게 하고 메소드에 쓰이면 메소드의 오버라이딩을 막고 변수에 쓰이면 변수의 값을 변경하지 못하는(상수) 녀석으로 만든다.
final 클래스를 사용하는 이유는 최종적으로 클래스를 만들고 하위클래스를 만들지 않을 때 사용한다. 생각해보면 어떤 클래스를 만들고 나서 배포를 했는데 제 3자가 이것을 확장하여 사용할수도 있다. final클래스를 쓴다는 것은 보안과 은닉성을 높여주는 역할을 한다.(예를 들면 System클래스나 String클래스같은 중요 클래스들도 API를 확인해보면 final로 선언되어있다.). final 처리가 된 class는 안쪽의 메소드들도 전부 final처리가 된다.
final메소드도 final클래스와 같은 역할을 한다. 다만 final메소드를 사용하면 컴파일러시 이 메소드를 inline화 하여 호출에 대한 부담을 줄여준다. 그렇기 때문에 실행속도가 상승되는 효과가 있다. inline인이란 메소드를 상수로 교체해주는 것인데 컴파일시에 상속을 받은 하위클래스의 메소드들은 호출을 할 때 오버라이딩 검사를 하게 된다. final를 붙이면 이 검사를 패스하게 된다.
final 변수는 절대 변하지 않는 변수를 만드는 것이다. final 변수를 초기화 하는 방식은 3가지가 있다. 첫번째 방법은 명시적으로 변수 생성시 초기화 하는 방법이고 두번째 방법은 초기화블록을 이용하여 초기화하는 방법, 세번째는 생성자를 이용하여 초기화하는 방법이 있다. 세번째 생성자를 이용하여 초기화 하는 방법은 새로 인스턴스를 생성할때 생성자의 매개변수를 이용하여 변수의 값이 다르게 초기화 하게 할 수 있다. 상수를 선언하는 방법중에 static final으로 선언하는 방법이 있다. 이것은 초기화를 할 때에는 명시적인 방법이나 static블록을 이용한 초기화 두가지만 가능하다. 생성자를 이용한 초기화가 불가능한 이유는 static 자체가 별도의 인스턴스이기 때문이다. 그렇기 때문에 생성자를 이용한 초기화는 불가능하다.
실무에서 소스를 짜다보면 final를 써야하는 경우는 위의 경우만 있는 것이 아니다. 예를 들어 안드로이드의 경우 리스너의 안쪽에 onCreate()에서 선언한 변수를 써야한다고 가정해보자. 이럴 경우에는 일반 변수는 값이 변할 수 있기 때문에 위젯변수.리스너 에서는 에러를 뱉어낸다. (변수에 final를 붙이라고 할 것이다.) 내가 프로젝트를 하면서 왜 스레드 인스턴스 밖에 변수를 쓰려고하면 자꾸 에러가 나면서 final를 붙이라고 했는지 이제서야 알았다....
아래는 예제 소스...
class TopFinal {
int mGlobalValue = 10;
final String mGlobalFinalValue = "Hellow";
final private String mBlankFinalName = "first Blank TopFinal(TopClass)";// 명시적
// 초기화.
final private String mFianlName;// 명시적 초기화를 하지 않을 경우 생성자를 통해서 초기화가 가능하다.
// 생성자를 이용하여 초기화 할 때에는 매개변수를 통하여 final이 붙은 변수도 다른 값을 가지는것이 가능
final private String mFinalBlockName;
{// 초기화블록에서 초기화
mFinalBlockName = "FinalBlock";
}
public TopFinal(String finalname) {
this.mFianlName = finalname;
}
public TopFinal() {
this.mFianlName = "생성자 초기화";
}
public void PrintFinal() {
// mDinotateFianlName =
// "Changed FinalDinotationValue (TopClass)";//final로 생성된 변수는 변경 불가
// mFianlName = "Changed FinalValue (TopClass)";
// mFinalBlockName = "Changed FinalBolckValue(TopClass)";
System.out.println("/////////////////////////////");
System.out.println("외부클래스에 선언된 final변수");
System.out.println("/////////////////////////////");
System.out.println("------------------------------");
System.out.println(mFianlName);
System.out.println(mBlankFinalName);
System.out.println(mFinalBlockName);
System.out.println("------------------------------");
}
}
final class SubFinal extends TopFinal {
static final String STATIC_FINAL_BLANK_NAME = "static Blank FinalValue";// static
// static final 명시적 초기화
static final String STATIC_FINAL_BLOCK_NAME;// static final block초기화
static {
STATIC_FINAL_BLOCK_NAME = "static fianl BlockValue";
}
// static final String STATIC_FINAL_NAME; // static final은 생성자에서 초기화 x
//
// public SubFinal(String staticFinalName) {
// // TODO Auto-generated constructor stub
// STATIC_FINAL_NAME = staticFinalName;
// }
public SubFinal(String finalname) {
super(finalname);
// TODO Auto-generated constructor stub
}
public final void PrintFinal() {
System.out.println("/////////////////////////////");
System.out.println("내부클래스에 선언된 static final변수");
System.out.println("/////////////////////////////");
System.out.println("------------------------------");
System.out.println(STATIC_FINAL_BLANK_NAME);
System.out.println(STATIC_FINAL_BLOCK_NAME);
System.out.println("------------------------------");
}
public final int PrintFianl() {// inline화로 인해 public final int PrintFinal()은
// 컴파일러에 의해 상수 3으로 변환.
return 3;
}
}
// class SonFinal extends SubFinal {
// public SonFinal(String finalname) {
// super(finalname);
// // TODO Auto-generated constructor stub
// }
//
// // finalClass는 참조 불가능
//
// public void PrintFinal() {// Error - final은 오버라이딩 불가능(컴파일시 오버라이딩 검사시 속도향상)
//
// }
//
// }
public class Final {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String test = "first FinalValue(Main)";
TopFinal topFinal = new TopFinal(test);
topFinal.PrintFinal();
System.out.println("<<<<<<<<<<<TopFinal class 전역변수 >>>>>>>>>>>>");
System.out.println(topFinal.mGlobalValue);
System.out.println(topFinal.mGlobalFinalValue);
System.out.println("<<<<<<<<<<<TopFinal class 전역변수 변경 >>>>>>>>>>>>");
topFinal.mGlobalValue = 200;
// topFinal.mGlobalFinalValue="안녕하세요.";//변경 불가능
System.out.println(topFinal.mGlobalValue);
System.out.println("<<<<<<<<<<<인스턴스 재생성>>>>>>>>>>>>");
String test1 = "change FinalValue(Main) - mFinalName값만 변경 가능";
topFinal = new TopFinal(test1);
topFinal.PrintFinal();
System.out.println("<<<<<<<<<<<객체에 final 지정>>>>>>>>>>>>");
String test2 = "final Object Test";
final TopFinal topFinal2 = new TopFinal(test2);
topFinal2.PrintFinal();
// topFinal2 = new TopFinal(test1);//final로 한번 선언된 객체는 다른 인스턴스 생성 x.
System.out.println("<<<<<<<<<<<static final 변수 인스턴스 없이 호출>>>>>>>>>>>>");
System.out.println(SubFinal.STATIC_FINAL_BLANK_NAME);
System.out.println(SubFinal.STATIC_FINAL_BLOCK_NAME);
// SubFinal.STATIC_FINAL_BLANK_NAME = "changedFinalValue";// 상수이므로 변경 불가
// SubFinal.STATIC_FINAL_BLOCK_NAME = "changedFinalValue";
SubFinal subFinal = new SubFinal(test);
subFinal.PrintFinal();
System.out.println("<<<<<<<<<<<final 메소드 호출>>>>>>>>>>>>");
System.out.println(subFinal.PrintFianl());
}
}
'Java' 카테고리의 다른 글
다형성 (0) | 2012.04.03 |
---|---|
추상클래스(abstract), 인터페이스(interface) (0) | 2012.03.29 |
랩퍼클래스 (0) | 2012.03.26 |
카멜표기법 (0) | 2012.03.26 |
Java InnerClass(내부클래스) (0) | 2012.03.26 |