티스토리 뷰
인터페이스
- 일종의 추상 클래스
- 추상클래스와 달리 일반 메서드를 멤버로 가질 수 없음.
-JDK1.8부터 등장한 static 메서드, default 메서드는 예외
인터페이스 정의하는 방법
interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
public abstract 메서드이름(파라미터목록);
}
- 모든 멤버변수는
public static final
로 선언. (생략 가능) - 모든 메서드는
public abstract
로 선언. (생략 가능)- JDK1.8부터 등장한 static 메서드, default 메서드는 예외
인터페이스 구현하는 방법
- 인터페이스는 추상클래스와 마찬가지로 그 자체로 인스턴스를 생성할 수 없음
- 자신이 정의한 추상메서드의 body를 만들어주는 클래스를 작성해야 함.
class 클래스이름 implements 인터페이스이름{ //인터페이스에 정의된 추상메서드를 구현 }
```java
public class FighterTest {
}
class Fighter extends Unit implements Fightable {
@Override
public void attack(Unit u) {
//생략
}
@Override
public void move(int x, int y) { //반드시 public
//생략
}
}
interface Fightable extends Movable, AttackAble{
}
interface Movable {
void move(int x, int y);
}
interface AttackAble {
void attack(Unit u);
}
인터페이스 레퍼런스를 통해 구현체를 사용하는 방법(다형성)
- 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 담을 수 있다.
- 인터페이스 타입의 참조변수로 해당 인터페이스를 구현한 클래스의 인스턴스를 담을 수 있다.
- 인터페이스 타입의 파라미터
- 해당 인터페이스를 구현한 클래스의 인스턴스를 파라미터로 제공해야 함을 의미
- 인터페이스 타입의 리턴타입
- 해당 인터페이스를 구현한 클래스의 인스턴스를 반환해야 함을 의미
public class ParserTest {
public static void main(String[] args) {
Parseable parser = ParseManager.getParser("XML");
parser.parse("doc.xml");
parser = ParseManager.getParser("HTML");
parser.parse("doc.html");
}
}
interface Parseable{
void parse(String fileName);
}
class ParseManager{
public static Parseable getParser(String type) {
if (type.equals("XML")) {
return new XMLParser();
} else {
return new HTMLParser();
}
}
}
class XMLParser implements Parseable {
@Override
public void parse(String fileName) {
System.out.println(fileName + " XML parsing complete");
}
}
class HTMLParser implements Parseable {
@Override
public void parse(String fileName) {
System.out.println(fileName + " HTML parsing complete");
}
}
- 위 코드에서 만약 XMLParser 를 NewXMLParser로 바꾸고 싶다면? ParserTest 의 클라이언트 코드는 전혀 바꿀 필요가 없이 NewXMLParser를 구현한 후,
return new XMLParser()
->return new NewXMLParser()
로 바꾸면 된다.
인터페이스 상속
- 오직 인터페이스로부터만 상속 가능
- 클래스와 달리 다중 상속 가능
- 클래스의 상속과 마찬가지로, 자손 인터페이스는 조상 인터페이스에 정의된 멤버를 모두 상속 받음
인터페이스 사용 예시
서로 관계없는 클래스들에게 관계를 맺어줄 때
직접적인 두 클래스 간의 관계를 간접적인 관계(의존적이지 않은 관계)로 변경할 때. 혹은 강한 결합을 느슨한 결합으로 바꾸고자 할 때.
public class InterfaceTest2 { public static void main(String[] args) { A a = new A(); a.autoPlay(new B()); a.autoPlay(new C()); } } class A { void autoPlay(I i) { i.play(); } /* void autoPlay(B b){ b.play(); } */ } interface I { public abstract void play(); } class B implements I { @Override public void play() { System.out.println("B.play"); } } class C implements I { @Override public void play() { System.out.println("C.play"); } }
인터페이스의 기본 메소드 (Default Method), 자바 8
- 자바8 이전에는 인터페이스에 메소드를 하나 추가한다는 것은, 추상 메서드를 만드는 일이었고 이는 해당 인터페이스를 구현한 모든 클래스가 추가된 메소드를 구현해야 함을 의미했다. 즉, 매우 번거롭고 복잡한 일이었다.
- 자바8부터 추가된 디폴트 메소드는 추상 메소드의 기본적인 구현을 제공한다. 따라서 디폴트 메소드를 새로 추가하더라도 해당 인터페이스를 구현한 클래스들을 변경할 필요가 없다.
interface MyInterface {
void method();
default void newMethod(){}
}
public class DefaultMethodTest {
public static void main(String[] args) {
Child c = new Child();
c.method1(); //Child.method1
c.method2(); //Parent.method2
}
}
class Child extends Parent implements MyInterface, MyInterface2{
@Override
public void method1() {
System.out.println("Child.method1"); //Interface 간 default method 충돌 해결
}
}
class Parent {
public void method2() {
System.out.println("Parent.method2"); //Interface - 조상 클래스 간 method 충돌시 우선 순위를 가짐
}
}
interface MyInterface{
default void method1() {
System.out.println("MyInterface.method1");
}
default void method2() {
System.out.println("MyInterface.method2");
}
static void staticMethod() {
System.out.println("MyInterface.staticMethod");
}
}
interface MyInterface2 {
default void method1() {
System.out.println("MyInterface2.method1");
}
default void staticMethod() {
System.out.println("MyInterface2.staticMethod");
}
}
- default 메소드 네이밍 충돌 -> default 메소드를 오버라이딩
- default 메소드 - 조상 클래스 메소드 네이밍 충돌 -> 조상 클래스의 메소드가 우선순위를 갖는다. 즉, default 메소드는 무시된다.
인터페이스의 static 메소드, 자바 8
Static 메소드는 인스턴스와 관계가 없는 독립적인 메소드이기 때문에 인스턴스에 추가하지 못할 이유가 없었음. -> JDK1.8 부터는 인스턴스에 static 메소드 추가 가능
- static 메서드의 접근 제어자는 항상 public. -> 생략 가능
- 참고로, Collection 인터페이스 - Collections 클래스가 있다. 만약 자바가 처음부터 인터페이스에 static 메소드를 제공했다면, Collections 클래스는 만들어지지 않았을 것.
인터페이스의 private 메소드, 자바 9
- 인터페이스 내부에서 코드 재사용성 향상
- 규칙
- private 메소드는 추상 메소드로 선언 불가
- 해당 인터페이스 내부에서만 사용 가능
- private static 메소드는 해당 인터페이스 내부 static, non-static 메소드에서 사용 가능
public class InterfacePrivateMethodTest {
}
interface CustomInterface {
default void method1() {
method3(); //private method 호출
method4(); //private static method 호출
}
static void method2() {
method4(); //private static method 호출 가능
System.out.println("static method");
}
private void method3() {
System.out.println("private method");
}
private static void method4() {
System.out.println("private static method");
}
}
백기선님 리뷰 영상
Spring HandlerInterceptor
- java8 이후 Interface - 구현 클래스 사이에 추상 클래스를 넣을 필요가 없어짐.
- default 메소드를 이용해 반드시 구현하지 않아도 되는 메소드를 추가할 수 있기 때문
default 메소드 사용시 diamond inheritance 문제 해결 방법
- Interface이름.super.메소드명 으로 해결
추상 클래스 - 인터페이스 관계
- 추상 클래스 : is-a
- 인터페이스 : has-a
추상 클래스의 필요성?
- 추상 클래스에서 제공하는 것을 인터페이스에서 모두 구현할 수 있는가?
- No.
- e.g. private 필드 변수 & setter 는 추상 클래스에서만 사용 가능.
- 추상 클래스에서 제공하는 것을 인터페이스에서 모두 구현할 수 있는가?
함수형 인터페이스
강한 결합, 느슨한 결합
- 인터페이스를 쓰는 이유
- 느슨한 결합을 해야(인터페이스를 쓰면) 코드를 바꿔끼기 좋다. 클라이언트 코드를 수정할 필요가 없음
References
'JAVA' 카테고리의 다른 글
[자바 스터디] 9주차 : 멀티쓰레드 프로그래밍 (0) | 2022.02.20 |
---|---|
[자바 스터디] 8주차 : 예외 처리 (0) | 2022.02.11 |
[자바 스터디] 6주차 : 상속 (0) | 2022.01.30 |
[자바 스터디] 5주차 : 클래스, 패키지 (0) | 2022.01.21 |
[자바 스터디] 4주차 : 제어문 (0) | 2022.01.15 |
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 객체지향
- java
- 프록시
- 토비의스프링
- SOLID
- 프로그래머스
- 메서드레퍼런스
- ec2
- 프록시패턴
- 서비스추상화
- 김영한
- 토비
- 디자인패턴
- 백기선
- 카카오
- provider
- 자바
- c++
- BOJ
- 데코레이터패턴
- 코딩테스트
- gracefulshutdown
- 예외처리
- 토비의봄TV
- 자바스터디
- AOP
- 코테
- OOP
- 템플릿콜백
- 스프링
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함