JAVA

[Java] 인터페이스

songsua 2024. 12. 6. 22:14

순수 추상 클래스를 편리하게 사용할 수 있도록 "인터페이스" 라는 기능을 제공한다.

 

인터페이스는 class 가 아니라 interface 키워드를 사용하면 된다.

 

순수 추상 클래스는 다음과 같은 특징을 가졌다

1. 인스턴스를 생성할 수 없다.

2. 상속 시 모든 메서드를 오버라이딩 해야 한다.

3. 주로 다형성을 위해 사용된다.

 

인터페이스의 특징은

1. 인터페이스의 메서드는 모든 public, abstract 이다.

2. 메서드에 public abstract 를 생략할 수 있다.

3. 인터페이스는 다중 구현을 지원한다.

인터페이스에는 모든 멤버 변수는 public static final 이 모두 포함되었다고 간주한다. 
#final 은 변수를 한번 설정하면 수정 불가

인터페이스는 구현이라고 정의하기 때문에 점선으로 표현한다.

 

package poly.basic.ex4;

public interface InterfaceAnimal {
    void sound();
    void move();
    
}

 

인터페이스는 일반적으로 상속할 목적으로 사용되기 때문에 pubilc이 기본으로 사용된다.

package poly.basic.ex4;

public class Dog implements InterfaceAnimal {
    @Override
    public void sound() {
        System.out.println("Dog sound");
    }

    @Override
    public void move() {
        System.out.println("Dog move");
    }
}
package poly.basic.ex4;

public class Cat implements InterfaceAnimal{
    @Override
    public void sound() {
        System.out.println("cat sound");
    }

    @Override
    public void move() {
        System.out.println("cat move");
    }
}

인터페이스는 extends 라는 용어를 사용하지 않는 implements를 사용한다.

package poly.basic.ex4;

public class InterfaceMain {
    public static void main(String[] args) {
        //인터페이스 생성불가
        
        Cat cat  = new Cat();
        Dog dog = new Dog();
        
        soundMain(cat);
        soundMain(dog);
    }
    
    public static void soundMain(InterfaceAnimal animal) {
        System.out.println("동물소리 테스트 시작");
        animal.sound();
        System.out.println("동물소리 테스트 종료");
        animal.move();
    }
}
cat sound
동물소리 테스트 종료
cat move
동물소리 테스트 시작
Dog sound
동물소리 테스트 종료
Dog move

 

그럼 상속 vs 구현 용어 차이

부모 클래스의 기능을 자식 클래스가 상속 받을 때 상속이다.

부모 인터페이스의 기능을 자식이 상속 받을 때는 인터페이스를 구현한다고 한다.

이렇게 다르게 사용하는 이유는 "상속" 은 부모의 기능을 물려받는 것이 목적이지만, "구현" 은 모든 메서드가 추상 메서드이며,

따라서 물려받을 수 있는 기능이 없고, 오히려 인터페이스에 정의한 모든 메서드를 자식이 오버라이딩 해서 기능을 구현해야 한다.

상속과 구현은 사람이 표현하는 단어만 다를 뿐이지 자바 입장에서는 같다.

 

인터페이스를 사용하는 이유

1. 제약: 인터페이스를 구현하는 곳에서 인터페이스의 메서드를 반드시 구현해라는 제약을 해주기 때문에 사용한다. 인터페이스는 모든 메서드가 추상 메서드이기 때문에 이 제약이 틀어질 일이 없다.

2. 다중 구현: 자바에서 클래스 상속은 부모를 하나만 지정할 수 있다. 반면, 인터페이스는 부모를 여러명 두는 다중 구현이 가능하다.

 

그러나 자바8에서 default 를 사용하면 인터페이스에서도  메서드를 구현할 수 있다.

 

 

 

인터페이스 다중구현

 자바는 다중 상속을 지원하지 않는다. 그래서 extends 대상은 하나만 선택할 수 있다. 부모를 하나만 선택할 수 있다는 뜻이다.

다중 상속 그림

만약 비행기와 자동차를 상속 받아서 하늘을 나는 자동차를 만든다고 가정해보자.

만약 그림과 같이 다중 상속을 사용하게 되면 AirplaneCar 입장에서 move()를 호출할 때 어떤 부모의 move()를 사용해야 할지, 애매한 문제가 발생한다. 이것을 다이아몬드 문제라고 한다.

그리고 다중 상속을 사용하면 클래스 계층 구조가 매우 복잡해질 수 있다. 

하지만, 인터페이스는 다중 상속이 허용된다. 왜냐면 인터페이스는 모두 추상메서드로 이루어져 있기 때문이다.

 

위와 같이 methodCommon() 을 둘다 가지고 있을 때, 어느 부모의 메서드를 사용할지 고민하는 것이 아닌,

Child 인터페이스 안에 있느 methodCommon()을 호출하면 된다. 따라서 다이아몬드 문제는 발생하지 않는다.

package poly.basic.diamond;

public interface InterfaceA {
    void methodA();
    void methodCommon();
}
package poly.basic.diamond;

public interface InterfaceB {
    void methodB();
    void methodCommon();
}
package poly.basic.diamond;

public class Child implements InterfaceA, InterfaceB {
    @Override
    public void methodB() {
        System.out.println("Child methodB");
    }

    @Override
    public void methodA() {
System.out.println("Child.methodA");
    }

    @Override
    public void methodCommon() {
     System.out.println("Child.methodCommon");
    }
}
package poly.basic.diamond;

public class DiamondMain {
    public static void main(String[] args) {
        InterfaceA a = new Child();
        a.methodA();
        a.methodCommon();
        InterfaceB b = new Child();
        b.methodB();
        b.methodCommon();
    }
}

 

어차피 오버라이딩된 애들이 호출된다.