Item21, 22 - 인터페이스 구현 및 주의

2023. 12. 3. 14:42java/이펙티브 자바

 

Item21 - 인터페이스는 구현하는 쪽을 생각해 설계하라.

기존 인터페이스에 디폴트 메서드 구현을 추가하는 것은 위험한 일이다.

 

 디폴트 메소드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메소드를 재정의하지 않은 모든 크래스에서 디폴트 구현이 쓰이게 된다. 그렇지만 추가된 메소드가 기존 구현체들과 매끄럽게 연동되리란 보장이 없다. 자바8 이전의 클래스들은 인터페이스가 한번 정의되면 그 이후에 추가되는 메서드가 없다는 가정하에 만들어졌기 때문이다.

 

 

인터페이스를 설계할 때는 세심한 주의를 기울여야 한다.

 디폴트 메서드는 기존 구현체에 런타임 오류를 일으킬 수도 있으니 기존 인터페이스에 디폴트 메소드는 꼭 필요한 경우인 경우에만 추가하자

public class SuperClass {

	//private!!
    private void hello() {
        System.out.println("hello");
    }
}

==============================================================================

public interface MarketInterface {
    default void hello() {
        System.out.println("hello");
    }
}

==============================================================================

public class SubClass extends SuperClass implements MarketInterface{

    public static void main(String[] args) {
        SubClass subClass = new SubClass();
        subClass.hello();
    }
}

=>
Exception in thread "main" java.lang.IllegalAccessError: class effective.study.chapter04.item21.SubClass tried to access private method 'void effective.study.chapter04.item21.SuperClass.hello()' (effective.study.chapter04.item21.SubClass and effective.study.chapter04.item21.SuperClass are in unnamed module of loader 'app')
	at effective.study.chapter04.item21.SubClass.main(SubClass.java:7)

 

subClass에서 호출한 hello() 메서드는 인터페이스의 hello() 디폴트 메서드가 아니라 SuperClass의 hello() 메서드를 호출해 private 한 메서드를 호출했다고 에러가 난다.

 

새로운 인터페이스를 설계할 때는 테스트를 충분히 해보고 기존 인터페이스에 디폴트 메소드는 꼭 필요한 경우에 추가하자

 

 

 

Item22 - 인터페이스는 타입을 정의하는 용도로만 사용하라

 

상수를 정의하는 용도로 인터페이스를 사용하지 말 것!

public interface PhysicalConstants {
    // 아보가드로 수 (1/몰)
    static final double AVOGADROS_NUMBER   = 6.022_140_857e23;

    // 볼츠만 상수 (J/K)
    static final double BOLTZMANN_CONSTANT = 1.380_648_52e-23;

    // 전자 질량 (kg)
    static final double ELECTRON_MASS      = 9.109_383_56e-31;
}

===================================================================

public class MyClass implements PhysicalConstants{

    public static void main(String[] args) {
        System.out.println(BOLTZMANN_CONSTANT);
    }
}

 - 클래스 내부에서 사용할 상수는 내부 구현에 해당한다.

 - 내부 구현을 클래스의 API로 노출하는 행위가 된다.

   => 캡슐화가 깨짐

 - 클라이언트에 혼란을 준다.

   => MyClass를 사용할 때 인터페이스가 어떤 의미를 가지는지, 데이터 타입을 인터페이스로 사용해야 하는지 등등

 

상수를 정의하는 방법

 - 특정 클래스나 인터페이스

   => 특정 클래스나 인터페이스에 강하게 연관된 상수일 경우

 - 열거형

 - 인스턴스화 할 수 없는 유틸리티 클래스

public class PhysicalConstants {
    private PhysicalConstants() { }  // 인스턴스화 방지

    // 아보가드로 수 (1/몰)
    public static final double AVOGADROS_NUMBER = 6.022_140_857e23;

    // 볼츠만 상수 (J/K)
    public static final double BOLTZMANN_CONST  = 1.380_648_52e-23;

    // 전자 질량 (kg)
    public static final double ELECTRON_MASS    = 9.109_383_56e-31;
}