# final
final 키워드는 변수(variable), 메서드(method), 클래스(class)에 사용될 수 있다.
이 final 키워드는 어떤 곳에 사용되냐에 따라 다른 의미를 가진다. 하지만 final 키워드를 붙이면 무언가를
제한다는 공통적 의미를 가진다.
final 변수(variable)
변수에 final을 붙이면 이 변수는 수정할 수 없다는 의미를 가진다. 수정될 수 없기 때문에 초기화 할 때
필수로 값을 넣어야 한다. 만약 객체 안의 변수라면 생성자, static 블럭을 통한 초기화까지는 허용한다.
수정할 수 없다는 범위는 그 변수의 값에 한정한다. 즉 다른 객체를 참조 할 때 참조하는 객체의 내부 값은
변경할 수 있다는 의미다.
// fanal 변수 선언 예시
public class Service {
public void variableFinal() {
final int value = 2;
final Person person = new Person("사바라다", 29);
System.out.println("value = " + value);
System.out.println("person_1 = " + person);
// value = 2; // 컴파일 에러
person.setAge(10);
person.setName("사바라");
System.out.println("person_2 = " + person);
// person = new Person("염광호", 29); // 컴파일 에러
}
}
class Person {
private String name;
private int age;
//.. get, set, toString 메서드 존재하나 길이상 생략
}
결과
value = 2
person_1 = Person{name='사바라다', age=29}
person_2 = Person{name='사바라', age=10}
변수를 final로 선언하고 초기화 전에 사용하면 컴파일 에러가 발생한다.
일반적인 초기화 방법
(1) 메서드 내부 변수
public void variableFinal() {
final int value = 2; //선언시 초기화
final int value_2; //사용하기 전 초기화
System.out.println("value = " + value);
value_2 = 3;
System.out.println("person_2 = " + value_2);
}
(2) 객체 멤버 변수
public void variableFinal() {
Person person = new Person("사바라다");
System.out.println("person = " + person);
}
class Person {
private final String name;
private final int age; //초기화 block을 이용한 초기화
{
age = 10;
}
private final String email = "koangho93@naver.com"; //선언시 초기화
public Person(String name) { //생성자를 이용한 초기화
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", email='" + email + '\'' +
'}';
}
}
(3) static 변수
class Person {
private static final String DEFAULT_NAME = "염광호"; //선언시 초기화
private static final int DEFAULT_AGE;
static { //static 초기화 block을 이용한 초기화
DEFAULT_AGE = 10;
}
... person 객체 내부 후략
# final 메서드(method)
메서드에 final을 붙이면 override를 제한하게 된다. 원래 클래스를 상속하게 되면 부모클래스의
protected, public의 접근제어자를 가진 메서드를 상속받아 재구현을 할 수 있다. 즉 동일한
메서드지만 다르게 동작하게 만들 수 있다는 말이다. 하지만 상속받은 클래스에서 해당 메서드를
수정해서 사용하지 못하게 할 수 있는 방법이 메서드에 final을 붙이는 방법이다.
public class Pet {
public final void makeSound() {
System.out.println("ahaha");
}
}
public class Dog extends Pet {
//final로된 메서드는 override할수 없음
public void makeSound() {
}
}
메서드 인자에 final 키워드를 붙이면 메서드 안에서 변수값을 변경할 수 없다.
public class Pet {
int weight;
public void setWeight(final int weight) {
//weight = 1; //final 인자는 메서드안에서 변경할 수 없음
}
}
# final 클래스(class)
클래스에 final을 선언하면 상속 자체가 안된다. 그냥 클래스 그대로 사용해야 한다.
Util 형식의 클래스나 여러 상수 값을 모아둔 Constants 클래스을 final로 선언한다.
public final class Pet {
}
//Pet 클래스가 final 클래스로 선언되어 상속할 수 없음
public class Dog extends Pet {
}
(1) 상수 클래스
public final class Constants {
public static final int SIZE = 10;
}
//public class SubConstants extends Constants {
//}
(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;
'JAVA > JAVA2' 카테고리의 다른 글
[java2] #20 - Thread (스레드) (0) | 2022.07.28 |
---|---|
[java2] #19 - IntStream 반복문 (0) | 2022.07.27 |
[java2] #17 - Collection Framework(Set/List/Map), Iterator (0) | 2022.07.26 |
[java2] #16 - HashSet (0) | 2022.07.26 |
[java2] #15 - HashMap (0) | 2022.07.25 |