자바는 순수 추상 클래스를 더 편리하게 사용할 수 있는 인터페이스라는 기능을 제공한다.
package poly.ex4;
public abstract class AbstractAnimal {
public abstract void sound();
public abstract void move();
}
인터페이스는 class 가 아니라 interface 키워드를 사용하면 된다.
package poly.ex5;
public interface InterfaceAnimal {
public abstract void sound();
public abstract void move();
}
package poly.ex5;
public interface InterfaceAnimal {
void sound();
void move();
}
순수 추상 클래스는 다음과 같은 특징을 가진다.
인터페이스는 앞서 설명한 순수 추상 클래스와 같다. 여기에 약간의 편의 기능이 추가된다.
package poly.ex5;
public interface InterfaceAnimal {
public static final int MAX_AGE = 100;
}
인터페이스에서 맴버 변수는 public, static, final 이 모두 포함되었다고 간주된다. final 은 변수의 값을 한번 설정하면 수정할 수 없다는 뜻이다.
자바에서 static final 을 사용해 정적이면서 고칠 수 없는 변수를 상수라 하고, 관례상 상수는 대문자에 언더스코어(_) 로 구분한다.
해당 키워드는 다음과 같이 생략할 수 있다. (생략이 권장된다.)
package poly.ex5;
public interface InterfaceAnimal {
int MAX_AGE = 100;
}
클래스 상속 관계는 UML 에서 실선을 사용하지만, 인터페이스 구현(상속) 관계는 UML 에서 점선을 사용한다.
package poly.ex5;
public interface InterfaceAnimal {
void sound();
void move();
}
package poly.ex5;
public class Cat implements InterfaceAnimal {
@Override
public void sound() {
System.out.println("야옹");
}
@Override
public void move() {
System.out.println("고양이 이동");
}
}
package poly.ex5;
public class Dog implements InterfaceAnimal {
@Override
public void sound() {
System.out.println("멍멍");
}
@Override
public void move() {
System.out.println("강아지 이동");
}
}
package poly.ex5;
public class Caw implements InterfaceAnimal {
@Override
public void sound() {
System.out.println("음메");
}
@Override
public void move() {
System.out.println("소 이동");
}
}
package poly.ex5;
public class AbstractMain {
public static void main(String[] args) {
// 인터페이스 생성 불가
// InterfaceAnimal animal = new InterfaceAnimal();
InterfaceAnimal[] animals = {new Dog(), new Cat(), new Caw()};
for (InterfaceAnimal animal : animals) {
animal.sound();
animal.move();
}
}
}
멍멍
강아지 이동
야옹
고양이 이동
음메
소 이동
부모 클래스의 기능을 자식 클래스가 상속 받을 때, 클래스는 상속 받는다고 표현하지만, 부모 인터페이스의 기능을 자식이 상속 받을 때는 인터페이스를 구현한다고 표현한다. 이렇게 서로 다르게 표현하는 이유를 알아보자.
상속은 이름 그대로 부모의 기능을 물려 받는 것이 목적이다. 하지만 인터페이스는 모든 메서드가 추상 메서드이다. 따라서 물려받을 수 있는 기능이 없고, 오히려 인터페이스에 정의한 모든 메서드를 자식이 오버라이딩 해서 기능을 구현해야 한다. 따라서 구현한다고 표현한다.
모든 메서드가 추상 메서드인 경우 순수 추상 클래스를 만들어도 되고, 인터페이스를 만들어도 된다.
그런데 왜 인터페이스를 사용해야 할까? 단순히 편리하다는 이유를 넘어서 다음과 같은 이유가 있다.
좋은 프로그램은 제약이 있는 프로그램이다.