▣ 목표
자바의 인터페이스에 대해 학습하세요.
▣ 학습할 내용
-
인터페이스 정의하는 방법
-
인터페이스 구현하는 방법
-
인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
-
인터페이스 상속
-
인터페이스의 기본 메소드 (Default Method), 자바 8
-
인터페이스의 static 메소드, 자바 8
-
인터페이스의 private 메소드, 자바 9
▶8-1 인터페이스 정의하는 방법
클래스를 선언하는 것과 유사하다. class라는 키워드 대신 interface라는 키워드를 사용해서 선언한다.
interface Example{
}
접근지시자로는 public과 default를 사용할 수 있다. 보통 클래스의 멤버들과 달리 인터페이스의 멤버들은 제약조건이 있다.
-> (인터페이스에 선언된) 모든 멤버변수는 public static final이어야 하고, 이를 생략할 수 있다.
-> (인터페이스에 선언된) 모든 메서드는 public abstract여야 하고, 이를 생략할 수 있다.
**생략된 접근제어자는 컴파일 타임에 컴파일러가 자동으로 추가해주기 때문에 생략할 수 있다.
BUT!!! JDK 1.8 부터 추가된 static method와 default method는 구현 강제성을 낮추고 유연하게 구현할 수 있도록 개선되었다.
▶8-2 인터페이스 구현하는 방법
추상클래스와 마찬가지로 그 자체로는 인스턴스를 생성할 수 없고, 인터페이스도 추상클래스와 같이 인터페이스 안에 정의된 멤버들을 사용해 구현해줄 클래스를 작성해야한다. 추상클래스는 확장하는 의미의 'extends' 키워드를 사용하지만 인터페이스는 구현한다는 의미의 'implements' 키워드를 사용한다.
public interface Example {
}
public class ExampleImpl implements Example {
}
구현 가능한 방법들을 나열하자면,
1. 단일 구현 (1개의 인터페이스) : 하나의 인터페이스만 구현
public interface Cafe {
}
public class Coffee implements Cafe {
}
2. 다중 구현 : 여러개의 인터페이스를 구현
public interface Drink {
}
public interface Dishes {
}
public class Menu implements Drink, Dishes {
}
3. 상속과 구현을 동시에 : 하나의 추상클래스를 상속받고, 1~N개의 인터페이스를 구현한다.
public interface Korean {
}
public interface Asian {
}
public abstract class Person {
}
public class Student extends Person implements Asian, Korean {
}
▷ 인터페이스와 추상클래스의 차이점
인터페이스는 추상클래스처럼 추상메서드를 갖고 있지만 추상클래스보다 추상화 정도가 높다.
추상클래스는 바디를 가진 일반메서드 또는 멤버변수를 가질 수 있지만 인터페이스는 추상메서드와 상수만 멤버로 가질 수 있다.
추상클래스는 "is-a : ~는 ~이다" 개념이라면, 인터페이스는 "has-a : ~는 ~를 가질 수 있다.(할 수 있다.)"의 개념으로 구분지을 수 있다.
▶8-3 인터페이스 레퍼런스를 통해 구현체를 사용하는 방법
public interface Animal {
String getName();
int getLegs();
}
public class Tiger implements Animal {
@Override
public String getName(){
return "호랑이";
}
@Override
public int getLegs(){
return 4;
}
}
public class Bird implements Animal {
@Override
public String getName(){
return "새";
}
@Override
public int getLegs(){
return 2;
}
}
Animal 인터페이스를 선언하고 추상메서드를 선언하고 Tiger와 Bird클래스에서 Animal 인터페이스를 구현한다.
Tiger tiger = new Tiger();
Bird bird = new Bird();
System.out.println(tiger.getName()); // 호랑이
System.out.println(tiger.getLegs()); // 4
System.out.println(bird.getName()); // 새
System.out.println(bird.getLegs()); // 2
각 클래스의 인스턴스를 생성하고 오버라이드해서 구현된 메서드들을 호출할 수 있다.
Animal tiger = new Tiger();
Animal bird = new Bird();
public void printAnimal(Animal animal){
System.out.println("이름 : "+animal.getName());
System.out.println("다리 개수 : "+animal.getLegs());
}
printAnimal(tiger);
printAnimal(bird);
객체 지향 언어의 특징인 다형성(Polymorphism)을 활용하여 Animal 타입으로 인스턴스 생성도 가능하다. Animal타입의 파라미터를 받는 메서드가 있다면 위의 예시처럼 Tiger와 Bird타입의 인스턴스도 인자로 사용될 수 있다.
▶8-4 인터페이스 상속
인터페이스는 인터페이스로부터만 상속받을 수 있다. 클래스와 달리 다중상속, 즉 여러 인터페이스로부터 상속받는 것이 가능하다. (extends 키워드를 사용한다고 다중상속이 불가능한 게 아니다..)
※ 참고로 인터페이스는 클래스와 달리 Object와 같은 최상위 인터페이스가 존재하지 않는다.
interface A {
void testAMethod();
}
interface B {
void testBMethod();
}
interface C extends A, B { } // OK!
인터페이스 C에 선언된 멤버가 없지만 부모 인터페이스로부터 상속받은 두 개의 추상메서드 testAMethod와 testBMethod를 자동으로 멤버로 갖게된다.
▶8-5 인터페이스의 기본 메서드 (Default Method), 자바 8
기존 인터페이스에는 추상메서드만 선언할 수 있었는데 자바 8버전부터 default 메서드가 도입되었다. 인터페이스에 메서드를 추가한다는 것은, 이를 구현하는 모든 클래스들이 추가된 메서드를 override해야하므로 번거로운 작업이 될 수 있다. 8버전부터 추가된 default 메서드를 선언하면 기본적인 구현을 제공하는 메서드로 정의내리기 때문에 해당 인터페이스를 구현한 클래스들이 추가된 메서드를 override할 의무가 없어진다.
default 메서드는 앞에 키워드 default를 붙이고 이 역시 접근제어자는 public 이며 생략이 가능하다. 예외적으로 해당 인터페이스의 default 메서드와 구현 클래스의 메서드명이 일치하여 충돌이 생긴다면 override해서 메서드 간의 충돌을 방지한다. (인터페이스의 default메서드는 static메서드와 달리 상속이 가능하다.)
▷ default 메서드가 생긴 이유?
주된 이유는 라이브러리 업데이트 때문이라고 한다. 인터페이스는 라이브러리나 프레임워크에서 매우 많이 사용되는데 라이브러리를 업데이트할 때 인터페이스에 추가된 기능이 있다면 이를 구현한 클래스를 역시 같이 추가해줘야했다. 하지만 라이브러리 사용자가 해당 인터페이스를 구현한 클래스가 있다면 아직 구현되지 않은(오버라이드 되지 않은) 메서드가 있다고 컴파일 에러가 날 것이다. 이런 불편을 해소하기위해 default 메서드가 도입되었다고 한다.
▶8-6 인터페이스의 static 메서드, 자바 8
static 메서드 역시 자바 8버전부터 도입되었고 인스턴스와 관계없이 독립적인 메서드이기 때문에 인터페이스에 추가될 수 있었지만 인터페이스의 모든 메서드는 추상 메서드여야한다는 원칙을 깨지는 않았다. 이 원칙 때문에 인터페이스와 관련된 static 메서드는 별도의 클래스에서 정의내려야 했다.
대표적인 예는 Collections 클래스를 예로 들 수 있다. Collection 인터페이스 관련 static메서드들이 예전부터 존재하던 규칙때문에 Collections라는 클래스를 따로 만들게 되었다.
▷인터페이스의 default 메서드와 static 메서드를 적용한 예시
public interface Calculator {
public int plus(int a, int b);
public int multi(int a, int b);
default int execPlus(int a, int b){
return a+b;
}
static int execMulti(int a, int b){
return a*b;
}
}
public class CalculatorImpl implements Calculator {
@Override
public int plus(int a, int n){
return a+b;
}
@Override
public int multi(int a, int b){
return a*b;
}
}
public class InterfaceEx {
public static void main(String[] args){
Calculator cal = new CalculatorImpl();
int resultPlus = cal.plus(1,2);
int resultMulti = cal.multi(1,2);
System.out.println(resultPlus); // 3
System.out.println(resultMulti); // 2
int resultExecPlus = cal.execPlus(1,5);
System.out.println(resultExecPlus); // 6
int resultExecMulti = Calculator.execMulti(1,5) // 5
System.out.println(resultExecMulti);
}
}
// 출처 : https://dahyeee.tistory.com/entry/JAVA-interface-default-static%EB%A9%94%EC%86%8C%EB%93%9C
▶8-7 인터페이스의 private 메서드, 자바 9
자바 8버전 부터 가능해진 디폴트 메서드 사용으로 로직을 분리할 필요가 생겼다.
-> private 메서드는 인터페이스에서 반드시 구현을 마쳐야하며 추상메서드일 수 없다.
-> 구현체에서 구현할 수 없고, 자손 인터페이스에서도 상속이 불가능하다. 인터페이스
-> static/non-static 관계없이 메서드에 private 키워드를 붙일 수 있다.
백기선님의 자바 라이브 스터디 커리큘럼을 따라 공부하고 있습니다.
잘못된 점이나 보충할 부분이 있으면 코멘트 남겨주세요
작은 조언이 저에겐 성장의 원동력이 됩니다 :-)
'Java' 카테고리의 다른 글
[자바 스터디] #9 - 예외처리 (0) | 2021.02.18 |
---|---|
[자바 스터디] #7 - 패키지 (0) | 2021.02.17 |
[자바 스터디] #3 - 연산자 (0) | 2021.02.04 |
[자바 스터디] #2 - 데이터 타입, 변수 그리고 배열 (0) | 2021.01.27 |
[자바 스터디] #1 - JVM과 컴파일 (0) | 2021.01.26 |
댓글