읽는데 약 2분
인터페이스
인터페이스를 정의하는 방법
인터페이스란 메서드와 constant variable을 포함하는 추상적인 타입을 의미합니다. 이를 정의하려면 implements
사용하면 됩니다.
인터페이스의 특징은 다음과 같습니다.
1. constant variable
인터페이스 내에 선언된 변수들은 암시적으로 public
, static
, final
을 갖게 됩니다. 위 인터페이스를 컴파일 한 후 javap -v -p -c Electronic.class
명령어를 통해 직접 확인할 수 있습니다.
2. abstract method
인터페이스에서는 컴파일러가 메서드에 abstract
키워드를 추가해줍니다. int getElectricityUse();
에서 abstract
가 명시적으로 선언되지 않았음에도 클래스파일에서 추가된 모습을 확인할 수 있습니다. 하지만 default
, static
, private
키워드에는 해당되지 않습니다.
3. static method & default method
JAVA 8부터는 인터페이스 메서드에서 static
과 default
keyword를 활용해 메서드는 구현체를 가질 수 있게 되었습니다. 둘의 차이점은 static
메서드는 오버라이딩이 불가능 하지만 default
메서드는 오버라이딩이 가능하다는 점입니다.
만일 위 키워드가 없었다면 인터페이스에 새로운 기능을 추가하기 위해서는 해당 인터페이스를 구현한 클래스까지 영향을 미치게 됩니다. 즉, backward compatibility를 위해 default
키워드를 도입함으로써 인터페이스의 수정만으로 새로운 기능을 추가하도록 했습니다.
또한 static method에 접근할 때는 interfaceName.methodName()
을 통해서 접근해야합니다.
4. private method
JAVA 9부터 private
메서드가 추가되었습니다. static과 non-static으로 구현가능하므로 default
나 static
메서드에서 코드의 일정부분을 encapsulation할 수 있습니다.
[non-static]
[static]
interface는 필요한 기능들을 모아놓은 계약서라고 할 수 있습니다. 여러 클래스들에서 필요한 것들을 모아놓음으로써 abstraction을 실현합니다.
그리고 상위 클래스를 구현한 하위 클래스들은 상위 클래스처럼 행동할 수 있는 것과 마찬가지로 인터페이스를 구현한 클래스도 인터페이스처럼 행동할 수 있습니다. 즉, runtime polymorphism을 통해 유연한 프로그래밍을 가능하게 합니다.
public interface Shape {
String name();
}
Circle
클래스와 Rectangle
클래스는 Shape
인터페이스를 구현했습니다.
List<Shape> shapes = new ArrayList<>();
Shape circleShape = new Circle();
Shape squareShape = new Square();
shapes.add(circleShape);
shapes.add(squareShape);
for (Shape shape : shapes) {
System.out.println(shape.name());
}
반복문 내에서 구체적인 타입을 명시하지 않더라도 런타임에 shape에 해당하는 타입을 찾아 dynamic dispatch가 이루어짐을 확인할 수 있습니다.
Marker Interface
Marker 인터페이스는 어떠한 메서드나 상수도 포함하지 않은 인터페이스를 의미합니다. 이를 통해 런타임 타입 정보를 제공함으로써 컴파일러나 JVM이 추가적인 정보를 얻을 수 있도록 합니다.
자바 또한 Serializable
, Clonable
, Remote
와 같은 여러 built-in marker 인터페이스를 사용합니다.
만약 우리가 복사하고자 하는 객체의 클래스에 Clonable
인터페이스를 구현하지 않는다면 JVM은 CloneNotSupportedException
을 던집니다. 소스코드를 보면 실제로 아무것도 구현이 되어있지 않는 것을 알 수 있습니다.
예외를 던지는 부분은 native로 작성된 clone
메서드 안에서 확인할 수 있습니다.