[Java] final

PADO·2021년 1월 14일
1

Java

목록 보기
4/6
post-thumbnail

final 필드

final의 의미는 최종적이라는 뜻을 갖고 있다.

Final 필드는 초기값이 저장되면 이것이 최종적인 값이 되어서 프로그램 실행 도중에 수정할 수 없다.

final 필드의 초기값을 줄 수 있는 방법은 두가지이다.

첫 번째는 필드 선언시에 초기값을 주는 방법이며,

두 번째는 생성자를 통해 초기값을 주는 방법이다.

(만약 초기화되지 않은 final 필드를 그대로 남겨두면 컴파일 에러가 발생한다.)

1. 개요

final 키워드를 떠올릴 때면 그냥 상수로만 생각할 때가 종종 있습니다. final을 클래스, 메서드, 변수에 선언하면 조금씩 할 수 있는 부분들이 제안됩니다. 너무 당연한 내용이지만, 시간이 지니니까 기억에서 사라져버려서 이번에 다시 한번 상기하기 위해 정리를 해보았습니다.

자바에서 final 키워드는 여러 컨텍스트에서 단 한 번만 할당될 수 있는 entity를 정의할 때 사용됩니다. (위키피디아)

final 키워드는 총 3가지에 적용할 수 있습니다. 각각에 대해서 세부적으로 알아보죠.

  • final 변수
    • 원시 타입
    • 객체 타입
    • 클래스 필드
    • 메서드 인자
  • final 메서드
  • final 클래스

2. Final 변수

2.1 원시 타입

로컬 원시 변수에 final로 선언하면 한번 초기화된 변수는 변경할 수 없는 상수값이 됩니다

@Test
    public void test_final_primitive_variables() {
        final int x = 1;
			//x = 3; // 한번 assign되면 변경할 수 없음.
    }

2.2 객체 타입

객체 변수에 final로 선언하면 그 변수에 다른 참조 값을 지정할 수 없습니다. 원시 타입과 동일하게 한번 쓰여진 변수는 재변경 불가합니다. 단, 객체 자체가 immutable하다는 의미는 아닙니다. 객체의 속성은 변경 가능합니다.

@Test
    public void test_final_reference_variables() {
        final Pet pet = new Pet();
			//pet = new Pet(); //다른 객체로 변경할수 없음

        pet.setWeight(3); //객체 필드는 변경할 수 있음

    }

2.3 메서드 인자

메서드 인자에 final 키워드를 붙이면, 메서드 안에서 변수값을 변경할 수 없습니다.

public class Pet {
    int weight;
    public void setWeight(final int weight) {
	//weight = 1; //final 인자는 메서드안에서 변경할 수 없음
    }
}

2.4 맴버 변수

클래스의 맴버 변수에 final로 선언하면 상수값이 되거나 write-once 필드로 한 번만 쓰이게 됩니다. final로 선언하면 초기화되는 시점은 생성자 메서드가 끝나기 전에 초기화가 됩니다. 하지만, static이냐 아니냐에 따라서도 초기화 시점이 달라집니다.

  • static final 맴버 변수 (static final int x = 1)
    • 값과 함께 선언시
    • 정적 초기화 블록에서 (static initialization block)
  • instance final 맴버 변수 (final int x = 1)
    • 값과 함께 선언시
    • 인스턴스 초기화 블록에서 (instance initialization block)
    • 생성자 메서드에서

3. Final 메서드

메서드를 final로 선언하면 상속받은 클래스에서 오버라이드가 불가능하게 됩니다. Dog 객체는 Pet의 makeSound() 메서드를 재정의할 수 없습니다. 언제 사용하면 좋을까요? 구현한 코드의 변경을 원하지 않을 때 사용합니다. side-effect가 있으면 안 되는 자바 코어 라이브러리에서 final로 선언된 부분을 많이 찾을 수 있습니다.

public class Pet {
    public final void makeSound() {
        System.out.println("ahaha");
    }
}

public class Dog extends Pet {
    //final로된 메서드는 override할수 없음
     public void makeSound() { 

     }
}

4. Final 클래스

클래스에 final을 선언하면 상속 자체가 안됩니다. 그냥 클래스 그대로 사용해야 합니다. Util 형식의 클래스나 여러 상수 값을 모아둔 Constants 클래스을 final로 선언합니다.

public final class Pet {
}

//Pet 클래스가 final 클래스로 선언되어 상속할 수 없음
public class Dog extends Pet {
}

4.1 상수 클래스

상수 값을 모아준 클래스는 굳이 상속해서 쓸 이유는 없겠죠?

public final class Constants {
    public static final int SIZE = 10;
}

//public class SubConstants extends Constants {
//}

4.2 Util 형식의 클래스

JDK에서 String도 final 클래스로 선언되어 있습니다. 자바의 코어 라이브러리이기 때문에 side-effect가 있으면 안 되겠죠. 다른 개발자가 상속을 해서 새로운 SubString을 만들어 라이브러리로 다른 곳에서 사용하게 되면 유지보수, 정상 실행 보장이 어려워질 수 있습니다.

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
}

final 필드와 상수

상수 (static final)

일반적으로 불변의 값을 상수라고 부른다.

불변의 값을 저장하는 필드를 자바에서는 상수(constant)라고 부른다.

final 필드는 한 번 초기화되면 수정할 수 없는 필드이지만, final 필드를 상수라고 부르진 않는다.

왜냐하면 불변의 값은 객체마다 저장할 필요가 없는 공용성을 띠고 있으며, 여러 가지 값으로 초기화될 수 없기 때문이다.

final 필드는 객체마다 저장되고, 생성자의 매개값을 통해서 여러 가지 값을 가질 수 있기 때문에 상수가 될 수없다.

상수는 static이면서 final 이어야 한다.

static final필드는 객체마다 저장되지 않고, 클래스에만 포함된다. 한 번 초기값이 저장되면 변경할 수 없다.

(상수 이름은 대문자로 작성하는게 관례이며, 언더바(_)를 사용하여 단어들을 연결한다.)

static final double PI = 3.14159;

static final double EARTH_RADIUS = 6400;


final 클래스와 final 메서드

final 키워드는 클래스, 필드, 메소드 선언 시에 사용할 수 있다. final 키워드는 결코 수정될 수 없음을 뜻한다.

상속할 수 없는 final 클래스

클래스를 선언할 때 final을 class앞에 붙이게 된다면, 최종적인 클래스이므로 상속할 수 없는 클래스가 된다.

대표적인 예로는 자바 표준 API인 String 클래스가 있다.

public final class String {}
public class MyString extends String {} // FAIL

오버라이딩할 수 없는 final 메소드

메소드를 선언할 때 final 키워드를 붙이게 되면 최종적인 메소드이므로 오버라이딩(Overriding)할 수 없는 메소드가 된다. (자식 클래스에서 재정의 불가)

public class Car{
	..
	public final void drive(){
		System.out.println(“gogo sing!);
	}
	..
}
 
public class MyCar extends Car{
	..
	@Override
	public final void drive(){
	// 불가
	}
	..
}

0개의 댓글