학습한 내용을 정리한 포스팅입니다. 참고 문헌 내용이 직역 되어 어색한 문장이 있을 수 있습니다. 틀린 내용이 있다면 지적해주시면 감사하겠습니다.🙇🏻♀️
인터페이스는 추상메서드와 상수만 멤버로 가질 수 있다.
모든 메서드는 public abstract여야 하고 모든 멤버 변수는 public static final 이어야 한다. 그리고 이 둘은 생략이 가능하다. (static 메서드와 디폴트 메서드는 예외)
public interface GroupedInterpace extends Interface1, Interface2, Interface3 {
// constant declarations
// base of natural logarithms
double E = 2.718282;
//method signatures
void doSomething(int i, double x);
int doSomethingElse(String s);
}
인터페이스는 그 자체로는 인스턴스를 생성 할 수 없다 그렇기에 인터페이스를 구현할 클래스가 필요하다. 아래와 같이 인터페이스를 구현 할 수 있다.
class 클래스명 implements 인터페이스명 {
//인터페이스에 정의된 추상 메서드를 구현해야 된다.
}
만일 구현하는 인터페이스의 메서드 중 일부만 구현하면 해당 클래스는 abstract
를 붙여서 추상 클래스로 만들어줘야 한다.
또한 메서드를 오버라이딩 할 때 조상의 메서드보다 넓은 범위의 접근제어자를 지정해야하는 것이 인터페이스 구현에도 적용된다. 아래의 경우에서 move메서드가 public인 걸 볼 수 있는데 위에서 언급한 것 처럼 인터페이스 내의 메서드는 public abstract
가 생략된 것이기 때문에 구현시에 접근 제어자를 public
으로 해줘야 한다.
interface Movable {
void move(int x, int y);
}
class Monster implements Movable {
public void move(int x, int y) {
//메서드 내용
}
}
(사족: 지금도 내가 제대로 이해를 한건지 잘 모르겠다. 혹시 예제나 제가 써놓은 부분이 틀렸다면 꼭 지적.. 부탁드리겠습니다 ㅠㅅㅠ)
interface Attackable {
void attack();
}
class Pikachu implements Attackable {
@Override
public void attack(){
System.out.println("피카츄 백만볼트!!");
}
public void sleep(){
System.out.println("zzz...");
}
}
class Squirtle implements Attackable {
@Override
public void attack(){
System.out.println("몸통박치기!!");
}
}
public Attackable getMonster(String name){
if(name.equals("피카츄")) {
return new Pikachu();
} else if (name.equals("꼬부기)) {
return new Squirtle();
} else {
System.out.println("죄송합니다. 해당 몬스터는 아직 준비되지 않았습니다.");
}
}
위의 예제에서 getMonster의 리턴타입이 Attackable이기 때문에 Attackable인터페이스를 구현한 클래스들(Pikachu, Squirtle)의 인스턴스를 반환한다.
인터페이스 타입으로 선언한 객체는 구현 클래스 내에서 생성한 메서드와 필드를 사용할 수 없다. 위의 경우에서는 Pikachu의 sleep 메서드를 사용할 수 없다. 사용하고 싶다면 캐스팅을 해야한다.
인터페이스는 인터페이스로부터만 상속이 가능하고 여러개의 인터페이스로부터 상속을 받는 것이 가능하다.
interface Moveable {
void move(int x, int y);
}
interface Attackable {
void attack();
}
interface Fightable extends Moveable, Attackable {}
//Fightable에는 정의된 멤버가 없더라도 Moveable, Attackable에 정의 된 move와
//attack 메서드를 멤버로 갖게 된다.
인터페이스는 다중상속이 가능하다. 하지만 실제로 인터페이스로 다중 상속을 구현하는 경우는 거의 없다고 한다. 그 이유인 것이 다중 상속의 단점이 장점보다 더 크다고(상속을 여러개 받을 때 메서드의 선언부가 같거나 멤버 변수의 선언부가 같거나 하는 경우 어떤 조상으로 상속 받는 것인지 판단하기가 어렵다 등) 판단해서 자바에는 다중 상속을 포함하지 않았기 때문이다.(C++과 다르게)
디폴트 메서드는 추상 메서드의 기본적인 구현을 제공하는 메서드로 추상 메서드가 아니기 때문에 디폴트 메서드가 새로 추가 되어도 인터페이스를 구현한 클래스를 변경하지 않아도 된다.
interface example {
default void newMethod() {}
}
단, 새로 추가된 디폴트 메서드가 기존의 메서드와 이름이 중복되어 충돌하는 경우가 발생한다. 이 충돌을 해결하는 규칙 두 가지가 있다.
원래는 추상메서드만 인터페이스에 선언할 수 있었는데 JDK 1.8부터 static 메서드도 추가할 수 있게 되었다.
구현체의 인스턴스를 생성하지 않고 인터페이스만으로 바로 메서드를 호출 할 수 있다.
interface Example1 {
static void sayHello(){
System.out.println("안녕하세요");
}
}
public class ExampleClass {
public static void main(String[] args){
Example1.sayHello();
}
}
// 안녕하세요 출력됨.
자바9부터는 인터페이스의 메소드에 private 메소드가 추가되었다. private 메서드가 추가됨으로써 얻는 가장 큰 장점은 캡슐화(encapsulation)이다. 또한 코드의 중복도 막을 수 있다.
interfaces are able to use private methods to hide details on implementation from classes that implement the interface. As a result, one of the main benefits of having these in interfaces is encapsulation.
Another benefit is (as with private methods in general) that there is less duplication and more re-usable code added to interfaces for methods with similar functionality.(출처: https://www.baeldung.com/java-interface-private-methods)
예시)
인터페이스의 private 메서드 사용법
남궁성, 자바의 정석
https://docs.oracle.com/javase/tutorial/java/IandI/interfaceDef.html
https://www.baeldung.com/java-interface-private-methods
https://www.geeksforgeeks.org/private-methods-java-9-interfaces/