목표
자바의 인터페이스에 대해 학습하세요.
학습할 것 (필수)
- 인터페이스 정의하는 방법
- 인터페이스 구현하는 방법
- 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
- 인터페이스 상속
- 인터페이스의 기본 메소드 (Default Method), 자바 8
- 인터페이스의 static 메소드, 자바 8
- 인터페이스의 private 메소드, 자바 9
추상 클래스와 인터페이스의 차이점
추상 클래스(abstract class) | 인터페이스(interface) |
1. 일반 메소드 포함가능 | 1. 모든 메서드는 추상메서드 자바 8 이후 부터 default ,static 메소드 추가가능 |
2. 다중상속 불가능 | 2. 다중상속 가능 |
3. 상수, 변수 필드 포함가능 | 3. 상수필드만 포함가능 |
추상 클래스는 IS - A 이다. ( 개는 동물이다. )
인터페이스는 HAS - A 이다. ( 개는 수영을 할 수 있다. )
개는 동물인 것에 확실하지만, 어떤 개는 수영을 할 수도 있고, 못 할 수도 있다.
인터페이스 정의하는 방법
- 인터페이스를 정의할 때에는 키워드 interface 를 사용한다.
- 모든 필드는 public final static 이다.
- 모든 메소드는 public abstract 이다.
변수 a에는 final static 을 붙여주고, b에는 생략을 해봤다.
메소드 cry와 feed도 마찬가지로 하나는 생략을 했다.
그렇지만 컴파일 에러가 나지 않고 잘 실행이 되었다. 왜그럴까??
아래 바이트 코드를 살펴보면 모든 필드, 메소드에 자동으로 추가가 되있는 것을 확인할 수 있다.
컴파일러가 자동으로 추가를 해준다. 즉, 생략이 가능하다는 의미이다.
인터페이스 구현하는 방법
구현을 할 때에는 클래스를 상속받는 것처럼 extends(상속) 대신 implements(구현) 를 사용한다.
public interface Animal {
void cry();
}
public class Cat implements Animal {
public void cry() {
System.out.println("냐옹냐옹");
}
}
인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
인터페이스는 다형성을 이용해 구현할 수 있다.
자식 클래스의 인스턴스를 부모클래스의 참조변수로 참조하는 것이 가능하다는 의미이다.
인터페이스는 객체의 타입으로만 사용된다.
이 말은 상속에서와 같이 변수 선언 시에 객체의 타입으로 인터페이스를 사용할 수 있다는 것을 의미한다.
인터페이스 타입이 있을 때는 항상 인터페이스 타입 기반으로 코딩해야 한다.
List 인터페이스를 예를 들어보자.
List를 구현한 구현체들은 여러가지가 있다. (예: ArrayList, LinkedList ..등등) 아래와 같이 선언할 수 있다.
// 좋은 예 : 객체 타입을 인터페이스로 선언.
List<Integer> list = new ArrayList<Integer>();
// 나쁜 예 : 객체 타입을 클래스로 선언
ArrayList<Integer> list = new ArrayList<Integer>();
인터페이스 로 객체 타입을 선언하게 된다면, 추후에 클래스를 교체할 일이 생겼을 시에 클래스만 바꿔끼면 된다. 시스템이 유연해지게 만드는 것이다.
익명 구현 개체
인터페이스는 원칙적으로 객체화 될 순 없지만, 익명 객체를 통해서 인터페이스를 구현하는 일회용 객체를 만들 수 있다.
public interface MusicPlayer {
void play();
}
// .. main
MusicPlayer mp = new MusicPlayer() {
@Override
public void play() {
System.out.println("play the music!");
}
};
인터페이스에 선언된 추상 메소드를 오버라이드 해주면 된다.
인터페이스 상속
- 인터페이스 끼리 상속을 할 때에는 extends 키워드를 사용한다.
public interface A {
...
}
public interface B {
...
}
/* 다중 상속 가능 */
public interface C extends A, B {
...
}
- 인터페이스는 다중 구현이 가능하다.
- implements A, B, C ...
public interface Animal {
void cry();
}
public interface Pet {
void play();
}
public class Cat implement Animal, Pet {
public void cry() {
System.out.println("냐옹");
}
public void play() {
System.out.println("play!!");
}
}
- 클래스와 인터페이스를 동시에 상속(extends), 구현(implements)할 수 있다.
public class Animal {
public void cry() {
}
}
public interface Pet {
void play();
}
public class Cat extends Animal implements Pet {
public void cry() {
System.out.println("냐옹");
}
public void play() {
System.out.println("play!!");
}
}
인터페이스의 기본 메소드 (Default Method), 자바 8
- 자바 8 이후로 인터페이스는 기본 메소드(Default Method) 를 사용할 수 있게 되었다.
- 기존에는 인터페이스 내에 있는 메소드를 전부 다 오버라이딩 해야만 했지만, 기본 메소드는 반드시 구현할 필요 없다.
- 기본 메소드 (Defalut Method) 는 구현부(body) 를 가지게 된다.
인터페이스를 구현할 때에는 항상 추상 메소드를 전부 다 오버라이딩 해야만 했다.
하지만 내가 필요한 메소드(기능)만 오버라이딩 하고 싶다면??
(기존 방법) : 중간에 인터페이스를 구현하는 Adapter 클래스를 생성한다.
public interface JoinMember {
void preJoin();
void afterJoin();
}
만약 내가 preJoin 만 구현하고 싶다면? 모든 메소드를 전부 빈 메소드로 정의한다.
public class MemberAdapter implements JoinMember {
public void preJoin() { // 빈 메소드 정의 }
public void afterJoin() { // 빈 메소드 정의 }
}
MemberAdapter를 상속받아서 필요한 메소드만 오버라이딩 하면 된다!
public class HelloMember extends MemberAdapter {
/* 필요한 기능만 오버라이딩 */
@Override
public void preJoin() {
System.out.println("hello, member");
}
}
( 자바 8 이후 default 메소드 사용 가능 ! )
public interface Camera {
void takePhoto();
/* default Method */
default void takeVideo() {
System.out.println("take a Video!");
}
}
public interface MusicPlayer {
void playMusic();
}
public class SmartPhone implements Camera, MusicPlayer{
@Override
public void takePhoto() {
}
// takeVideo 메소드를 구현하지 않아도 된다.
@Override
public void playMusic() {
}
}
만약 interface에 동일한 default 메소드가 선언되어 있다면?
컴파일 에러가 발생하기 때문에, 무조건 overriding을 해야한다.
public interface Camera {
void takePhoto();
default void takeVideo() {
System.out.println("take a Video!");
}
default void print() {
System.out.println("camera");
}
}
public interface MusicPlayer {
void playMusic();
default void print() {
System.out.println("Music");
}
}
public class SmartPhone implements Camera, MusicPlayer{
@Override
public void takePhoto() {
}
// print()를 구현하지 않으면?
@Override
public void playMusic() {
}
}
동일한 메소드를 오버라이딩(Overriding) 하지 않으면? 아래처럼 컴파일 에러가 발생하게 된다!
인터페이스의 static 메소드, 자바 8
인터페이스의 추상성을 해친다는 이유로 제약을 걸어왔지만, 자바 8 부터는 개발의 유연성을 위해 static 메소드를 선언할 수 있게 되었다.
- static 메소드는 오버라이딩이 불가!
- default 나 abstract 메소드는 모두 instance 메소드 처럼 처리된다.
- default 메소드를 static 메소드로 덮으려 하면 안된다 -> 컴파일 에러!
public interface MusicPlayer {
static void info() {
System.out.println("Music Player!");
}
}
public class Main {
public static void main(String[] args){
MusicPlayer.info(); // Music Player!
}
}
인터페이스의 private 메소드, 자바 9
자바 9 이후로 private 메소드 접근제어자도 사용할 수 있게 되었다.
public interface Camera {
default void print() {
..
}
private void info() {
..
}
}
인터페이스에서도 default, static, private 기능이 추가되었는데, 추상클래스가 필요가 없어지는 것인가?
- 상태 존재 여부에 따라서
인터페이스는 필드에 상수만 선언 가능하고, private String 처럼 선언이 불가능 하다!
추상 클래스는 실행 중 변경이 필요할 때, 사용할 수 있다.
public abstract clas AbstractJoinMember implements JoinMember {
private String message = "hello"; // 이런게 가능
@Override
public void preJoin() {
System.out.println(message);
}
public void setMessage(String message) {
this.message = message; // 이런게 가능
}
}
이런 점 때문에 아직 까지도 추상 클래스에도 효용가치가 있다!
정리
public interface 인터페이스명 {
// 상수 : 값을 정해줄테니 제공해주는 값을 변경하지 말고 사용해라.
타입 상수명 = 값;
// 추상 메소드 : 가이드만 줄테니 구현부는 알아서 구현해라.
타입 메소드명(매개변수 ...);
// 디폴트 메소드 : 구현부는 기본적으로 인터페이스에서 제공하지만, 필요하면 오버라이딩해서 재구현해라.
default 타입 메소드명(매개변수 ...) {
// 구현부
}
// 정적 메소드 : 인터페이스에서 제공해주는 것으로 무조건 사용. 오버라이딩 불가!
static 타입 메소드명(매개변수 ...) {
// 구현부
}
}
REFERENCES
- www.notion.so/Java-8-0cc8c251d5374ac882a4f22fa07c4e6a
- github.com/ByungJun25/study/tree/main/java/whiteship-study/8week#Interface-%EB%A0%88%ED%8D%BC%EB%9F%B0%EC%8A%A4%EB%A5%BC-%ED%86%B5%ED%95%B4-%EA%B5%AC%ED%98%84%EC%B2%B4-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
- kils-log-of-develop.tistory.com/437
- leegicheol.github.io/whiteship-live-study/whiteship-live-study-08-interface/
- www.tcpschool.com/java/java_polymorphism_interface
- docs.oracle.com/javase/tutorial/java/IandI/interfaceAsType.html
- velog.io/@jaden_94/8%EC%A3%BC%EC%B0%A8-%ED%95%AD%ED%95%B4%EC%9D%BC%EC%A7%80#5-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%9D%98-%EA%B8%B0%EB%B3%B8-%EB%A9%94%EC%86%8C%EB%93%9C-default-method-%EC%9E%90%EB%B0%94-8