Jiny Jan 9, 2021 2021-01-09T14:09:00+09:00
Sep 4, 2021 2021-09-04T10:25:19+09:00 11 min
Java Interface
Interface
자바의 다형성을 극대화하여 개발코드 수정을 줄이고 프로그램 유지보수성을 높이기 위해 인터페이스를 사용
Interface 정의
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| public interface 인터페이스명 {
//상수
타입 상수명 = 값;
//추상 메소드
타입 메소드명(매개변수, ... );
//디폴트 메소드
default 타입 메소드명(매개변수, ... ){
//구현부
}
//정적 메소드
static 타입 메소드명(매개변수) {
//구현부
}
|
- 상수 : 인터페이스에서 값을 정해줄테니 함부로 바꾸지 말고 제공해주는 값만 참조 (절대적)
- 추상메소드 : 가이드 제공, 추상메소드를 오버라이팅해서 재구현 (강제적)
- 디폴트메소드 : 인터페이스에서 기본적으로 제공, 맘에 안들면 각자 구현 (선택적)
- 정적메소드 : 인터페이스에서 제공해주는 것으로 무조건 사용 (절대적)
인터페이스 구현
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| public interface Bank {
//상수 (최대 고객에게 인출해 줄 수 있는 금액 명시)
public int MAX_INTEGER = 10000000;
//추상메소드(인출하는 메소드)
void withDraw(int price);
//추상메소드(입금하는 메소드)
void deposit(int price);
//JAVA8에서 가능한 defualt 메소드(고객의 휴면계좌 찾아주는 메소드 : 필수구현은 선택사항)
default String findDormancyAccount(String custId){
System.out.println("**금융개정법안 00이후 고객의 휴면계좌 찾아주기 운동**");
System.out.println("**금융결제원에서 제공하는 로직**");
return "00은행 000-000-0000-00";
}
//JAVA8에서 가능한 정적 메소드(블록체인 인증을 요청하는 메소드)
static void BCAuth(String bankName){
System.out.println(bankName+" 에서 블록체인 인증을 요청합니다.");
System.out.println("전 금융사 공통 블록체인 로직 수행");
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| public class KBBank implements Bank{
@Override
public void withDraw(int price) {
System.out.print("KB은행만의 인출 로직...");
if(price < Bank.MAX_INTEGER){
System.out.println(price+" 원을 인출한다.");
}else{
System.out.println(price+" 원을 인출실패.");
}
}
@Override
public void deposit(int price) {
System.out.println("KB은행만의 입금 로직..."+price+" 원을 입금한다.");
}
}
|
Interface 와 abstract Class
차이점
- 추상 클래스는 일반 메서드와 추상 메서드 둘다 가질 수 있다.
- 인터페이스는 오로지 추상 메서드와 상수만을 가진다. (구현 로직을 작성할 수 없다.)
- but. java8 부터는 default method와 static method를 작성할 수 있다.
- 인터페이스 내에 존재하는 메서드는 무조건 “public abstract” 로 선언되며, 이를 생략할 수 있다.
- 인터페이스 내에 존재하는 변수는 무조건 “public static final” 로 선언되며, 이를 생략할 수 있다.
- Java는 상속은 하나만 implement는 여러개 할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
| // interface 의 제약 조건을 따르지 않았기 때문에 오류가 발생합니다.
private int a = 1;
// 컴파일러가 자동적으로 public static final b = 2로 추가해줍니다.
public int b = 2;
// 컴파일러가 자동적으로 public static final c = 3으로 추가해줍니다.
static int c = 3;
// 컴파일러가 자동적으로 public static final d = 4로 추가해줍니다.
int d = 4;
|
익명 구현 객체
구현 객체를 만드는 것이 일반적이나 일회성 객체를 위해 소스코드를 생성하고 인터페이스를 정의 하는 것은 비효율적 -> 익명 구현 객체
1
2
3
| 인터페이스 변수 = new 인터페이스(){
// 인터페이스에 선언된 추상 메소드의 실체 메소드 정의
}
|
Interface 상속, 구현체 사용
- 서브 인터페이스는 수퍼 인터페이스의 메서드까지 모두 구현해야 함
- 인터페이스 레퍼런스는 인터페이스를 구현한 클래스의 인스턴스를 가리킬 수 있고, 해당 인터페이스에 선언된 메서드(수퍼 인스턴스 메소드 포함)만 호출 할 수 있다.
Interface 다중 상속
Interface는 Class와 달리 다중 상속 가능
- 추상 메서드로 구현하기 전의 메서드이기 떄문에 어떤 인터페이스의 메서드를 상속받아도 같기 때문
- 메서드 명과 파라미터 형식은 같지만 리턴 타입이 다른 메서드가 있다면, 둘중 어떤 것을 상속받느냐에 따라 규칙이 달라지기 때문에 다중 상속이 불가능
1
2
3
| public interface Bar extends Foo {
void barMethod();
}
|
1
2
3
4
| public interface Foo {
void fooMethod();
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| public class DefaultFoo implements Bar {
@Override
public void barMethod() {
System.out.println("bar method - by DefaultFoo");
}
@Override
public void fooMethod() {
System.out.println("foo method - by DefaultFoo");
}
public void testMethod_1(){
System.out.println("test method _ 1");
}
public void testMethod_2(){
System.out.println("test method _ 2");
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| public class App {
public static void main(String[] args){
System.out.println("hi");
DefaultFoo defaultFoo = new DefaultFoo();
defaultFoo.fooMethod();
defaultFoo.barMethod();
defaultFoo.testMethod_1();
defaultFoo.testMethod_2();
Bar bar = defaultFoo;
bar.barMethod();
bar.fooMethod();
}
}
|
- Class Type 레퍼런스: 해당 클래스에 정의된 메서드 호출 가능
- Interface Type 레퍼런스: 해당 Interface를 구현한 클래스 인스턴스를 가르킬 수 있고 해당 Interface에 선언된 메서드만 호출할 수 있음
다중 Interface에서의 Interface Reference
한 클래스가 여러 개의 인터페이스를 구현했다면 각 인터페이스로 구분해서 그 객체를 사용 가능
- 구현체를 어떤 Interface Reference에 담느냐에 따라 사용할 때 따르는 규칙이 달라짐
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| public class App {
public static void main(String[] args){
System.out.println("hi");
DefaultFoo defaultFoo = new DefaultFoo();
defaultFoo.fooMethod();
defaultFoo.barMethod();
Bar bar = defaultFoo;
bar.barMethod();
bar.fooMethod();
Baz baz = defaultFoo;
baz.bazMethod();
}
}
|
Interface의 Default Method
- 인터페이스에 메소드 선언이 아니라 구현체를 제공하는 방법
- 해당 인터페이스를 구현한 클래스의 어떠한 영향없이 새로운 기능을 추가하는 방법
- default method 는 해당 인터페이스를 구현한 구현체가 모르게 추가된 기능임으로 그만큼 리스크가 따른다.
- 컴파일 에러는 발생하지 않지만, 특정한 구현체의 로직에 따라 런타임 에러가 발생할 수 있다.
- 사용하게 된다면, 구현체가 잘못사용하지 않도록 반드시 문서화 하자!
- Object가 제공하는 기능(equals, hashCode)와 같은 기본 메소드는 제공할 수 없다.
- 구현체가 재정의 하여 사용하는 것은 상관없다.
- 본인이 수정할 수 있는 인터페이스에만 기본 메소드를 제공할 수 있다.
- 인터페이스를 상속받은 인터페이스에서 다시 추상 메소드로 변경할 수 있다.
- 인터페이스 구현체가 default method를 재정의 할 수 있다.
static method
해당 인터페이스를 구현한 모든 인스턴스, 해당 타입에 관련되어 있는 유틸리티, 헬퍼 메소드를 제공하고 싶다면? → static method로 제공
Java 9
java9 에서는 추가적으로 private method 와 private static method 가 추가
- 단지 특정 기능을 처리하는 내부 method일 뿐인데도, 외부에 공개되는 public method로 만들어야 하기 때문
- 코드의 중복을 피하고 interface에 대한 캡슐화를 유지
ServiceLoader
인터페이스의 구현체를 주입받은 jar에 따라 선택할 수 있는 클래스