부모 클래스의 기능을 자식 클래스가 상속 받을 때, 클래스는 상속 받는다고 표현하지만, 부모 인터페이스의 기능을 자식이 상속받을 때는 인터페이스를 구현한다고 표현한다.
그럼 굳이 왜 다르게 표기할까?
상속은 이름 그대로 부모의 기능을 물려받는 것이 목적이다. 하지만 인터페이스는 모든 메서드가 추상 메서드이다. 따라서 물려받을 수 있는 기능이 없고, 오히려 인터페이스에 정의한 모든 메서드를 자식이 오버라이딩해서 기능을 구현해야 한다. 따라서 구현한다고 표현한다.
인터페이스는 메서드 이름만 있는 설계도이고, 이 설계도가 실제 어떻게 작동하는지는 하위 클래스에서 모두 구현해야 한다. 따라서 인터페이스의 경우 상속이 아니라 해당 인터페이스를 구현한다고 표현한다.
모든 메서드가 추상 메서드인 경우 순수 추상 클래스를 만들어도 되고, 인터페이스를 만들어도 되는데 왜 인터페이스를 사용함? 편리?
인터페이스를 만드는 이유는 인터페이스를 구현하는 곳에서 인터페이스의 메서드를 반드시 구현해라는 제약(규약)을 주는 것이다.
USB 인터페이스를 생각하면, USB 인터페이스에 맞추어 키보드, 마우스를 개발하고 연결해야 한다. 그렇지 않으면 작동하지 않는다. 인터페이스 제약은 반드시 구현해야 하는 것이다. 그런데 순수 추상 클래스의 경우 미래에 누군가 그곳에 실행 가능한 메서드를 끼워넣을 수 있다. 이렇게 되면 추가된 기능을 자식 클래스에서 구현하지 않을 수도 있기 때문에, 더는 순수 추상 클래스가 아니게 된다. 인터페이스는 이런 문제를 원천 차단한다.
자바에서 클래스 상속은 부모를 하나만 지정할 수 있다. 반면에 인터페이스는 부모를 여러명 두는 다중 상속이 가능하다.

InterfaceA, InterfaceB는 둘 다 같은 methodCommon()을 가지고 있다. 그리고 Child는 두 인터페이스를 구현했다.
상속 관계의 경우 두 부모 중에 어떤 한 부모의 methodCommon()을 사용해야 할지 결정해야 하는 다이아몬드 문제가 발생한다.
하지만 인터페이스 자신은 구현을 가지지 않는다. 대신에 인터페이스를 구현하는 곳에서 해당 기능을 모두 구현해야 한다. 여기서 InterfaceA, InterfaceB 같은 이름의 methodCommon()을 제공하지만 이것의 기능은 Child가 구현한다. 그리고 오버라이딩에 의해 Child에 있는 methodCommon()이 호출된다. 결과적으로 두 부모 중에 어떤 한 부모의 methodCommon()을 선택하는 것이 아니라 그냥 인터페이스들을 구현한 Child에 있는 methodCommon()이 사용된다. 이러한 이유로 인터페이스는 다이아몬드 문제가 발생하지 않는다.
public class InterfaceA {
void methodA();
void methodCommon();
}
public class InterfaceB {
void methodB();
void methodCommon();
}
public class Child implements InterfaceA, InterfaceB {
@Override
public void methodA() {
System.out.println("Child.methodA");
}
@Override
public void methodB() {
System.out.println("Child.methodB");
}
@Override
public void methodA() {
System.out.println("Child.methodCommon");
}
}
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();
}
}

public abstract class AbstractAnimal {
public abstract void sound();
public void move() {
System.out.println("동물이 이동합니다.");
}
}
public interface Fly {
void fly();
}
public class Dog extends AbstractAnimal {
@Override
public void sound() {
System.out.println("Dog_Sound");
}
}
public class Bird extends AbstractAnimal implements Fly {
@Override
public void sound() {
System.out.println("Bird_Sound");
}
@Override
public void fly() {
System.out.println("새 날기");
}
}
public class Chicken extends AbstractAnimal {
@Override
public static void sound() {
System.out.println("Chicken_Sound");
}
@Override
public void fly() {
System.out.println("닭 날기");
}
}
extends를 통한 상속은 하나만 할 수 있고, implements를 통한 인터페이스는 다중 구현 할 수 있기 때문에 둘이 함께 나온 경우 extends가 먼저 나와야 한다.
public class SoundFlyMain {
public static void main(String[] args) {
Dog dog = new Dog();
Bird bird = new Bird();
Chicken chicken = new Chicken();
}
// AbstractAnimal 사용가능
private static void soundAnimal(AbstractAnimal animal) {
animal.sound();
}
// Fly 인터페이스가 있으면 사용 가능
private static void flyAnimal(Fly fly) {
fly.fly();
}
}