책 정리/📌Practical 모던 자바
2장 인터페이스
by IMSfromSeoul
2021. 10. 30.
📌 인터페이스에 대한 변화
- 자바 아키텍쳐들에 java 8에서 함수형 프로그래밍이나 람다 등과 같은 새로운 기능들이 들어오면서, 인터페이스에 대한 변화가 생겼다.
- 인터페이스에 대한 변경은 java 7에서 시작됐으며, java 8에서 대대적으로 바뀌었다.
- 인터페이스의 default 메서드는 java 8에서 추가됐다.
📌 interface 사용시 문제점
인터페이스는 명세의 역할을 하므로 해당 인터페이스를 상속받은 구현체는 해당 인터페이스의 모든 메서드를 구현해야 한다.
- 위의 사항은 인터페이스의 장점이자, 동시에 단점이기도 하다.
- 왜냐하면 한번 배포된 인터페이스는 수정이 어려워지기 때문이다.
- 만약 배포된 인터페이스에 기능을 추가해야 하는 상황이 있다고 해보자. 그러면 아래와 같은 문제가 생길 수 있다.
1. 해당 interface를 상속받은 class는 모두 컴파일 에러가 발생한다. 그런데, 해당 interface를 상속받은 class가 너무 많아서, 전부 수정하는 것이 불가능하다.
2. 해당 interface를 회사 내부 뿐만 아니라, 외부에서도 사용하고 있다.
3. class를 수정하지 않고, interface를 compile해서 배포하면, 일부 소프트웨어에서 NoSuchMethod error가 발생할 수 있다.
🔥 해결방안 1) - 다른 인터페이스 상속
- 다른 해결방안으로, 새로운 인터페이스를 만들어서 해당 인터페이스를 상속받는 방법이 있다.
- 그러나 위의 방법도 한계가 있는데, 만약 기능이 100개가 추가돼서 100개의 인터페이스를 추가로 상속받는다고 하면 프로그램이 상당히 복잡해진다.
- 그래서 java에서도 Collection 인터페이스와, Collections 가 따로 존재한다.
- List의 경우, java 7까지는 collection 인터페이스에 sort 기능이 없어서 collections클래스를 활용해야 했지만, 8부터는 다른 클래스의 도움 없이 정렬을 할 수 있게 됐다.
📌 해결방안 -2) default, static, private method in interface
- java 8에서 인터페이스 기능을 대대적으로 변경했고, 그 핵심은 default method이다.
- 최초의 interface는 아래와 같은 제약이 있었다.
1. 상수를 선언할 수 없다. 해당 상수는 반드시 값이 할당 돼 있어야 하고, 값을 변경할 수 없다. 즉 final이다. 해당 변수는 final로 선언하지 않아도, final로 인식된다. 또한 interface는 멤버변수를 가질 수 없으므로, static으로 인식된다.
즉, int a = 3; 으로 선언했다고 하더라도, static final int a = 3; 으로 인식된다.
(4번까지 합쳐져서 public static final int a = 3; 으로 인식된다)
2. 메서드는 반드시 추상메서드(abstract)여야 한다. 즉, 구현체가 아니라 명세만 정의돼 있어야 한다.
3. 만약 인터페이스를 구현한 클래스가 해당 인터페이스에서 정의한 메서드를 전부 구현하지 않았다면, 해당 클래스는 반드시 abstract class 여야 한다.
4. 인터페이스에 선언된 상수와 메서드는 public으로 선언하지 않았다고 하더라도, public으로 인식된다.
- java 1.2부터 인터페이스에 중첩 클래스를 선언할 수 있게 바뀌었다.
- 중첩 클래스는 클래스나 인터페이스에 static으로 선언된 클래스이다. 인터페이스 내부의 클래스는 static으로 선언하지 않아도 자동으로 static이 붙으므로 인터페이스에 선언된 클래스는 모두 중첩 클래스가 된다. ( 내부 클래스와 중첩 클래스는 다르다 )
- java 8에서 인터페이스에 실제 코드가 완성돼 있는 static method를 선언할 수 있게 됐다.
- java 8에서 인터페이스에 실제 코드가 완성돼 있는 default method를 선언할 수 있게 됐다.
- java 9에서 인터페이스에 실제 코드가 완성돼 있는 private method를 선언할 수 있게 바뀌었다. 이는 java 8에서 deafult와 static에서 실제 코드를 사용할 수 있게 바뀌면서 생기게 된 코드의 중복을 줄이기 위한 변화이다.
- interface내부의 private과 static은 선언만 하는 것이 불가능하다. 반드시 구현을 해야한다.
📌 default method
- default method기능을 이용해서 인터페이스의 메서드를 추가한 대표적인 예는 List interface의 sort와 Collection interface의 stream method이다.
- default method는 안의 코드 내용이 실제로 구현돼 있으므로, 사실상 extends와 유사하다.
📌 default - static method 사용방법
- house 객체에서 사용할 수 있는 method는 default로 선언된 printBye() 메서드이다.
- 만약 static method를 사용하고 싶으면, 아래와 같이 클래스 형으로 사용해야 한다.
📌 추상 클래스 - 인터페이스 차이점
- 인터페이스에 default나 static method로 구현 코드가 들어갈 수 있게 됨으로써, 추상 클래스와의 경계가 모호해졌다고 느낄 수 있다.
- 인터페이스와 추상 클래스의 가장 큰 차이는 2가지이다.
1. 추상클래스는 멤버 변수를 가질 수 있다. 인터페이스는 멤버 변수를 갖지 못하고, 안에 선언된 변수들은 모두 static 변수들이다. 이는 인터페이스가 객체화를 할 수 없다는 의미이다.
2. 클래스는 다중상속이 안되지만, 인터페이스는 다중상속이 된다. 자바는 클래스간 다중 상속을 허용하지 않는다.
- default 메서드는 상속이 되며, 심지어 overriding할 수도 있다.
- 이 때, 상속받은 인터페이스의 default 메서드를 사용하고 싶다면 위와 같이 interface명.super.메서드명() 을 작성해주면 된다.
- cf) extends -> 인터페이스가 인터페이스를 상속받을 때는 implements가 아닌 extends를 사용한다.
📌 다이아몬드 상속
- 위와 같이, 상위 클래스를 상속받은 하위 클래스 2개를 다시 하나의 클래스가 동시에 상속받은 경우 다이아몬드 구조라고 부른다.
- 이 때의 문제는, 동일한 이름과 형태를 가진 메서드가 상위 클래스의 양쪽 모두에 정의돼 있을 경우 어떤 메서드를 실행할 지 모른다는 것이다.
📌 예제
Human.java
Man.java
Woman.java
Worker.java
- Worker class에서 Man과 Woman을 동시에 implements 받으니까, getSex를 재정의 하라고 컴파일 에러를 낸다.
📌 클래스 - 인터페이스 우선순위
- 만약 위의 구조에서 남자를 interface가 아닌 abstract class로 변경한다면, interface와 abstract 중 누가 우선순위를 갖게 될까?
댓글