6주차 때 상속을 공부하면서 우리는 자바에서 다중 상속이 불가능 한 것을 확인했다.
이는 우리가 구현하고 싶어하는 객체지향 프로그래밍에서는 상당한 제약사항이다.
자바를 개발한 사람들도 이 사실을 알고 있었지만 자바를 C++ 보다 더 안정적인 언어로 만들고 싶었다. 그를 위해 조금 덜 유연하게 설계 되었으며 더 적은 오류 발생을 보여준다.
이러한 제약 사항의 해결책으로 Interface
를 선택했다.
interface
는 클래스처럼 reference type
이다.
이름에서 알 수 있듯이 API
를 그저 표현하기만 한다.
다시 말하면 타입, 메소드, 클래스의 명세만 제공한다.
일반적으로 interface
는 body
를 작성하지 않는다. 그리고 interface
를 implementation
하는 클래스는 메소드를 반드시 오버라이딩 해야한다.
이러한 특징 때문에 표준화가 가능하며 표준화를 통해 개발 시간 단축이 가능하다.
클래스간의 관계 매핑도 가능하다.
interface Human {
void hello();
// Java8 부터 허용되는 default 키워드
// 메소드의 구현체를 포함시킬 수 있다.
default void sleep() {
System.out.println("zzZZ");
}
}
public abstract
메소드이다.abstract
키워드를 작성해도 되지만 convention
에 따라 생략한다.interface
의 멤버들은 암묵적으로 public
이지만 컨벤션을 따라 생략한다.interface
는 인스턴스 필드를 선언할 수 없다. static final
키워드가 함께하는 필드이다.interface
는 인스턴스화 시킬 수 없기 때문에 생성자를 정의하지 않는다.Nested Type
을 포함할 수 있다. 이는 암묵적으로 public static
키워드를 가진다.Java 8
부터 static method
를 포함할 수 있다. static method
는 body를 추가해야한다.Java 9
부터 private method
를 포함할 수 있다.private static
메소드는 또 다른 static
메소드나 static
메소드가 아닌 곳에서는 사용할 수 없다.non- static private
메소드는 private static
에서 사용할 수 없다.protected method
를 선언하려고 하면 컴파일 에러가 발생한다.인터페이스는 다른 인터페이스를 여러개 상속 받을 수 있다.
클래스와는 다르게 다중 상속이 가능하다.
interface Life {
// public static final 이 생략되어 있다.
// 따라서 초기화하지 않으면 선언이 불가능하다.
double breathInterval = 5;
void breath();
}
interface Human extends Life {
void hello();
default void sleep() {
System.out.println("zzZZ");
}
}
부모 인터페이스의 default method
는 오버라이딩이 가능하다.
클래스는 하나 이상의 interface
를 implements
할 수 있다.
작성 규칙은 다음과 같다.
implements
는 extends
키워드 이후에 작성해야한다.interface
는 ,
로 구분한다interface
에 명시된 메소드들의 body를 구현해야 한다.default method
는 다시 구현할 필요가 없다.public class American implements Human {
@Override
public void hello() {
System.out.println("Hello");
}
}
public class Korean implements Human {
@Override
public void hello() {
System.out.println("안녕하세요");
}
}
public interface Bug extends Life {
String head = "머리입니다";
String chest = "가슴입니다";
String body = "배입니다";
}
public interface Plant extends Life {
void photosynthesis();
}
public class Cordyceps implements Plant, Bug {
@Override
public void breath() {
System.out.println("숨은 여름 겨울 둘 다 쉽니다~");
}
@Override
public void photosynthesis() {
System.out.println("여름엔 식물이라서 광합성합니다~");
}
public void insect() {
System.out.println("겨울엔 곤충이라서 머리 가슴 배로 이루어져 있습니다~");
System.out.println(head);
System.out.println(chest);
System.out.println(body);
}
}
Human korean = new Korean();
korean.hello();
korean.sleep();
Human american = new American();
american.hello();
american.sleep();
Human
인터페이스를 구현하고 있는 Korean
과 American
은 Human
타입으로 생성될 수 있다. 이를 다형성이라고 한다.
이를 통해 어떤 메소드의 파라미터로 받을 수도 있다.
void test(Human human) {
// TODO
}
...
...
...
test(korean);
test(american);
이런식으로 Korean
과 American
을 받기 위해서 오버로딩하지 않고 인터페이스를 구현하고 있는 녀석들로 매개변수를 받을 수 있다.
Human
은 Life
의 자식 클래스이기 때문에 Life
로도 받을 수 있다.
void test(Life life) {
// TODO
}
...
...
...
test(korean);
test(american);
당연한 이야기지만 Life
로 받는다면 Human
에 정의된 메소드들은 사용할 수 없고 명시적으로 형변환을 통해서만 사용이 가능하다.
Human
을 받는test
와Life
를 받는test
가 동시에 존재할 때Human
을 받는test
가 동작한다.