인터페이스
인터페이스란 기본적으로 코드 수행부가 없는 추상 메소드로 구성된 것이다. 상속 가능한 추상 클래스와 유사하지만, 추상 메소드만 선언되어 있다는 점, 이 때문에 상속과 같이 클래스에 구현(일종의 상속)이 가능하고 이를 통해 다중 상속이 불가능한 자바에서 인터페이스를 통한 일종의 다중 상속이 가능하다는 점이 특징이다. 이를 통해 다형성과 유연성에 이점을 가진다.
기본적인 선언 문법은 아래와 같다.
access_modifier interface Name {
abstract public return_type method_name(parameter);
...
}
이때 인터페이스에 포함되는 추상 메소드는 자동으로 abstract
와 public
의 속성을 가지며, 따라서 생략할 수 있다.
앞서 말한 바와 같이 인터페이스는 추상 메소드만 구현되어 있기 때문에 인스턴스 필드를 가질 수 없다. 그러나 상수 필드는 가질 수 있다.
access_modifier interface Name {
abstract public return_type method_name(parameter);
public static final data_type name = data;
...
}
상수 필드만 가능하기 때문에 public static final
이 강제되고 따라서 생략할 수 있다.
인터페이스를 구현하는 클래스는 implements
키워드를 사용하여 해당 인터페이스를 불러온다.
class ClassName implements InterfaceName {
...
}
이렇게 어떤 클래스가 인터페이스를 구현했다면, 해당 클래스의 객체를 인터페이스 타입으로 업캐스팅 가능하다.
다중 상속
어떤 클래스가 인터페이스를 구현한다면 모든 추상 메소드를 구현해야 한다. 구현하지 않는다면 컴파일 에러가 발생한다.
클래스가 인터페이스를 구현할 때는 상속과 달리 여러 인터페이스를 구현 가능하다. 클래스 상속에서는 다중 상속이 불가능했지만, 인터페이스는 가능한 것이다. 어차피 인터페이스의 메소드는 추상 메소드이기 때문에 여러 인터페이스를 구현해야 할 때도 문제가 발생할 가능성이 낮다.
다음과 같이 하나의 클래스에서 여러 인터페이스를 구현할 수 있다.
class ClassName implements InterfaceName1, InterfaceName2, InterfaceName3 {
...
}
더하여 인터페이스도 인터페이스를 상속받을 수 있는데, 이때도 다중 상속이 가능해진다. 즉 아래와 같은 상속이 가능하다.
interface InterfaceName extends InterfaceName1, InterfaceName2, InterfaceName3 {
...
}
앞서 객체가 인터페이스 타입으로 업캐스팅 가능하다고 하였는데, 다중 인터페이스를 구현하는 클래스는 구현하는 모든 인터페이스 타입으로 업캐스팅이 가능하고, 구현하는 인터페이스가 다른 인터페이스를 상속받은 경우, 구현하는 인터페이스가 상속받은 인터페이스 타입으로도 업캐스팅 가능하다.
디폴트 메소드
인터페이스의 특정 메소드가 정해진 동작을 해야한다고 가정해보자. 그런데 인터페이스가 추상 메소드만을 가진다면 인터페이스를 구현하는 각 클래스마다 정해진 동작을 일일이 구현해주어야 한다. 그런데 소수의 클래스가 해당 인터페이스를 구현한다면 큰 문제없이 사용할 수 있지만, 다수의 클래스가 해당 인터페이스를 구현해야 한다고 가정해보자. 모든 클래스에서 해당 메소드를 구현해주어야 하는데, 심지어 같은 동작을 해야한다. 이렇게 되면 해당 메소드를 수정해야 될 때 모든 클래스를 수정해야 하고, 때문에 클래스에서 해당 메소드를 구현하면서 실수가 일어나기 쉽다.
이러한 문제들을 방지하기 위해서 인터페이스 내에서도 메소드를 구현하여 사용할 수 있는데, 이것이 default
키워드를 이용한 디폴트 메소드이다. 반드시 오버라이딩 되어야 하는 추상 메소드와 달리 디폴트 메소드는 선택적으로 재정의가 가능하다. Java 8 에서 추가되었으며 앞으로의 설명은 Java 8 기준이다.
access_modifier interface Name {
abstract public return_type method_name(parameter);
default public return_type method_name(parameter) {
...
}
...
}
추상 메소드와 마찬가지로 public
이 강제되므로 생략 가능하다.
단 추상 메소드만 구현되어 있는 인터페이스의 경우 메소드 충돌 문제가 생길 일이 없었지만, 디폴트 메소드는 서로 다른 동작을 하는 메소드가 구현될 수 있기 때문에 메소드 충돌 가능성이 생겼다. 따라서 디폴트 메소드를 구현하는 클래스에서 디폴트 메소드를 재정의하거나 충돌 가능성이 있는 디폴트 메소드를 만들지 않는 등으로 충돌을 방지해야 한다.
정적 메소드
기존 클래스 내에서도 정적 메소드가 있었다. 인터페이스에서도 같은 방식으로 정적 메소드 선언 및 사용이 가능하다. 기존 인터페이스 메소드와 다르게 재정의될 수 없고, 반드시 인터페이스 이름을 통해서 호출하고 사용해야 한다는 특징이 있다.
access_modifier interface Name {
static return_type method_name(parameter) {
...
}
...
}
'Language > Java' 카테고리의 다른 글
[Java] 간단한 텍스트 파일 입출력 (0) | 2024.11.20 |
---|---|
[Java] 예외(exception)와 예외 처리(exception handling) (0) | 2024.11.19 |
[Java] abstract 키워드를 통한 추상 클래스와 추상 메소드 (0) | 2024.11.14 |
[Java] 업캐스팅(upcasting)과 다운캐스팅(downcasting) (0) | 2024.11.12 |
[Java] 클래스 상속(inheritance) (0) | 2024.11.12 |