이따금 단순히 static 메서드와 static 필드만을 담은 클래스를 만들고 싶을 때가 있습니다.
(객체 지향적이지 못해서 남용하면 좋지않지만.. 나름의 쓰임새가 있다!)
java.lang.Math 와 java.util.Arrays처럼 기본 타입 값이나 배열 관련 메서드들을 모아놓을 수 있습니다.
java.util.Collections 처럼 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드 혹은 정적 팩터리 메서드를 모아놓을 수 있습니다.
(자바 8부터 이런 메서드를 인터페이스에 모아둘 수 있습니다.)
final 클래스와 관련한 메서드들을 모아놓을 때도 사용합니다.
-> final 클래스를 상속해서 하위 클래스에 메서드를 넣는 건 불가능하기 때문입니다.
정리하면
static 메서드와 static 필드만 담을 클래스를 사용하는 경우
- 기본 타입 값이나 배열 관련 메서드들을 모아놓고 싶은 경우
- 특정 인터페이스를 구현하는 객체를 생성해주는 정적 메서드 혹은 정적 팩터리를 모아놓는 경우
- final 클래스와 관련한 메서드들을 모아놓고 싶은 경우
보통 이렇게 만든 클래스가 유틸리티 클래스입니다.
유틸리티 클래스는 인스턴스로 만들어서 사용하려고 설계한것이 아니기 때문에 생성자의 존재가 필요없습니다.
그렇다고 생성자를 명시하지 않는걸로 끝낸다면?
- 컴파일러가 친절하게 기본 생성자를 추가해줍니다.
아래는 생성자를 명시하지 않은 클래스 입니다.
package item4_20210420;
public class PrivateConstructorEx1 {
void doSomething() {
System.out.println("뭔가를 실행");
}
}
위의 코드를 컴파일한 뒤
-> 바이트 코드를 디컴파일한 파일을 보면 아래와 같이 기본 생성자가 추가되어 있습니다.
추상 클래스로 만드는 것으로는 인스턴스화를 막을 수 없습니다. 하위 클래스를 만들어서 인스턴스화 하면 그만입니다.
package item4_20210420;
public class PrivateConstructorEx2 {
public static void main(String[] args) {
MyAbstractClass myAbstractClass = new MyChildClass();
}
}
abstract class MyAbstractClass {
void doSomething() {
System.out.println("뭔가를 할겁니다.");
}
}
class MyChildClass extends MyAbstractClass {
@Override
void doSomething() {
System.out.println("자식이 뭔가를 합니다.");
}
}
더불어 추상클래스를 본 사용자는 상속해서 쓰라는 뜻으로 오해할 수도 있습니다.(아이템 19)
따라서 컴파일러가 기본 생성자를 만드는 경우는 오직 명시된 생성자가 없을 때뿐이니
간단하게 기본 생성자를 private 생성자로 추가하면 클래스의 인스턴스화를 막을 수 있습니다.
package item4_20210420;
public class UtilityClass {
// 기본 생성자가 만들어지는 것을 막는다(인스턴스화 방지용)
private UtilityClass() {
throw new AssertionError();
}
void doSomething() {
System.out.println("뭔가를 실행함");
}
}
기본 생성자의 접근자를 private 로 명시했으니 클래스 바깥에서는 기본 생성자에 접근할 수 없습니다.
즉, 클래스 외부에서는 인스턴스를 생성할 수 없습니다.
꼭 AssertionError()를 던질 필요는 없지만, 클래스 안에서 실수로라도 생성자를 호출하지 않도록 해줍니다.
그런데 "생성자가 분명 존재하는 데 호출할 수 없다니? " 라고 착각할 수 있고 직관적이지 않을 수 있습니다.
그래서 위의 코드처럼 적절한 주석을 달아두도록 합니다.( 주석도 싫지만.. )
이 방식은 상속을 불가능하게 하는 효과도 있습니다.
모든 생성자는 명시적이든 묵시적이든 상위 클래스의 생성자를 호출하게 되는데 ( 예시. super() )
상위 클래스의 생성자가 private 로 선언되어 있으니 하위 클래스가 접근할 길이 막혀있습니다.
'이펙티브 자바' 카테고리의 다른 글
[아이템 6] 불필요한 객체 생성을 피하라 (0) | 2021.04.22 |
---|---|
[아이템 5] 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2021.04.22 |
[아이템 3] private 생성자나 열거 타입으로 싱글턴임을 보증하라 (0) | 2021.04.20 |
[아이템 2] 생성자에 매개변수가 많다면 빌더를 고려하라 (0) | 2021.04.18 |
[아이템 1] 생성자 대신 정적 팩터리 메서드를 고려하라 (0) | 2021.04.17 |
댓글