인터페이스 정의
인터페이스
자바 인터페이스는 자바 프로그래밍 언어의 초기 버전부터 존재한다.(Java 1.0, 1996년)
인터페이스는 추상화의 한 형태로, 메서드의 선언만 있고 구현 내용이 없는 추상 메서드들로 이루어져있다.
클래스가 이 모든 메서드들을 구체적으로 구현해야한다.
선언
모든 기능을 추상화로 정의한 상태로 선언만 해야한다
접근 제어자로는 public 또는 default를 사용한다
interface MyInterface {
void myMethod();
}
내장 인터페이스
이미 자바에서는 다양한 내장 인터페이스가 있다. 아래 그림과 예시를 보면 인터페이스와 클래스간의 관계,
필요성이 더 잘 느껴지지않을까 싶다.
아래는 내장되어있는 Collection의 구조이다.
그마저도 일부분이고 실제로 자바안에서 쓰게되면 이렇게 다양한 인터페이스랑 클래스가 상속과 구현으로 엮여있다
구현 관련해서는 밑에 한번더 언급이 있기때문에 실제 자바 정의내용에서 어떻게 구현되어있는지는 밑에 작성하겠다
인터페이스 사용 이유
- 개발 기간을 단축 및 표준화 가능
단축시킬 수 있는 이유는 협업시 다른 개발자들이 각각의 부분을 완성할때까지
기다리지 않고 서로 규약만 정해두어 각자의 부분만 따로 나눠서 코드를 작성하면된다.
또한 규약을 정해두었기에 크게 다를부분이 존재하지 않는다 - 클래스간 결합도를 낮춤
코드의 종속성을 줄이고 유지 보수성을 높이도록 해준다
추상클래스 vs 인터페이스의
의미
추상클래스는 "is - a: ~는 ~이다" 의개념
인터페이스는 "has-a: ~는 ~를 할 수 있다" 의 개념
사용시기
- 추상 클래스
- 여러개의 가까운 클래스들 사이에 동일한 코드를 공유해서 사용하고 싶을때 사용한다
- 인터페이스
- 다중 구현상속의 이점을 누려야할때 사용한다
- 추가로 데이터타입의 행위를 구현하길 원할때 사용한다
인터페이스 구현
결국 인터페이스가 가진 메서드는 추상메서드이고 이제 객체가 그것을 구현해줘야한다
이러한 객체를 인터페이스의 구현객채라고 한다.
구현클래스
보통의 클래스와 동일한데, 인터페이스 타입으로 사용할 수 있음을 알려주기 위해 클래스 선언부에
implements 키워드를 추가하고 인터페이스 명을 명시해야한다.
MyInterface.java
public interface MyInterface {
void myMethod();
}
Myclass.java - 구현클래스이자 myMethod 구현
public class MyClass implements MyInterface {
@Override
public void myMethod(){ //구현
System.out.println("myMethod가 호출되었다");
}
}
MyInterface의 추상 메서드인 myMethod를 구현한 모습이다.
Main.java
public class Main {
public static void main(String args[]) {
MyInterface myInterface = new MyClass();
myInterface.myMethod();
}
}
//실행시 'MyMethod가 호출되었다'
추가로 아까 위에서 봤던 큐 인터페이스의 add 추상메서드를
AbstractQueue 구현 클래스에서 구현한 모습이다.
다중 인터페이스 구현 클래스
객체는 다수의 인터페이스 타입으로 사용할 수 있다.
따라서 이런 모양이 가능하다
이렇게 사용할 경우 구현 클래스는 모든 인터페이스의 추상메서드에 대해 실체 메서드를 작성해야한다
마커 인터페이스(내용과 크게 상관없음)
자바 내부에 저장된 인터페이스 문서를 읽는 와중에 메서드가 존재하지 않는 인터페이스를 발견했다
Serializable
찾아보니 Serializable은 마커 인터페이스로 분류되며, 실제로 추상 메서드를 정의 하지 않는다.
마커인터페이스 정의
메서드나 필드를 가지고 있지않고, 단지 클래스가 특정한 특성, 능력 또는 상태를 가지고 있는것을 나타내기 위해 사용되는 인터페이스이다. 이러한 인터페이스는 런타임에 클래스의 특성을 나타내는데 사용되며, 특정한 동작이나 메서드 구현을 강제하지 않는다. 또다른 예시로는 Cloneable이 있다.
인터페이스 래퍼런스 통해 구현체 사용방법
인터페이스를 상속 받은 클래스는 인터페이스 래퍼런스로 클래스를 가리킬 수 있다.
사용 예시는 다음과 같다.
MyInterface.java
public interface MyInterface {
void myMethod();
}
MyClass1.java
public class MyClass1 implements MyInterface {
@Override
//MyInterface의 myMethod구현
public void myMethod() {
System.out.println("MyClass1의 myMethod가 호출");
}
}
MyClass2.java
public class MyClass2 implements MyInterface {
@Override
//myMehtod구현
public void myMethod() {
System.out.println("MyClass2의 myMethod가 호출");
}
}
Main.java
public class Main {
public static void main(String[] args) {
//인터페이스 레퍼런스를 선언 및 구현클래스 참조
MyInterface obj1 = new MyClass1();
MyInterface obj2 = new MyClass2();
//인터페이스 레퍼런스를 통해 구현클래스의 메서드를 호출
obj1.myMethod();
obj2.myMethod();
}
}
//출력문
//MyClass1의 myMethod가 호출
//MyClass2의 myMethod가 호출
인터페이스를 사용하지 않았을때와 사용했을때를 비교했을때의 특징
- 사용자가 더이상 구현 클래스에 의존하지 않고 인터페이스에 의존한다(인터페이스를 쓰지 않았더라면 사용자는 2개의 클래스에 의존했어야 할것이다)
- 인터페이스인 MyInterface는 다형성을 제공한다, 래퍼런스를 통해 구현체를 사용하고 있다는 것을 알 수 있다
인터페이스 상속
인터페이스도 클래스처럼 다른 인터페이스를 상속할 수 있다. 이를 통해 여러 인터페이스를 결합하여
하나의 새로운 인터페이스를 정의할 수 있다. 키워드는 'extends'를 사용하고 예시는 아래와 같다.
InterfaceA.java
public interface InterfaceA {
void methodA();
}
InterfaceB.java
public interface InterfaceB {
void methodB();
}
MyInterface
public interface MyInterface extends InterfaceA, InterfaceB{
void methodA(); //상속받은 메서드
void methodB();
void myMethod();
}
위와같이 상속받은 메서드는 필수적으로 한번더 명시해줘야한다.
문제가 있는경우
다중 상속시 메서드의 이름이 같고 리턴타입이 다를경우 문제가 발생한다
아래는 InterfaceA, InterfaceB에 같은 이름의 메서드가 존재하는데 하나는 ing형, 하나는 Void로 설정해뒀는데 다음과 같은 오류가 뜬다. 따라서 리턴타입은 맞춰줄 필요가 있다.
다중상속의 문제점
1.다이아몬드 문제
서로 다른 인터페이스에서 같은 메서드를 상속받는다면, 해당 메서드를 구현하는
클래스에서 명시적으로 어떤 메서드를 호출할지 지정해야한다.
2.메서드 시그니처
두개 인터페이스를 구현하는 경우 메서드 시그니쳐가 같은 케이스는 중복되는 인터페이스의 추상 메서드를 재정의 하여 사용할 수 있다.
메서드 시그니처 해결법
- 클래스가 항상 이긴다. 클래스나 슈퍼클래스에서 정의한 메서드가 디폴트 메서드보다 우선권을 갖는다.
- 1번 규칙 이외의 상황에서는 서브 인터페이스가 이긴다. 상속관계를 갖는 인터페이스에서 같은 시그니처를 갖는 메서드를 정의할때는 서브 인터페이스가 이긴다. 즉, B가 A를 상속받는다면 B가 A를 이긴다.
- 여전히 디폴트 메서드의 우선순위가 결정되지 않았다면 여러 인터페이스를 상속받는 클래스가 명시적으로 디폴트 메서드를 오버라이드라고 호출해야한다
인터페이스의 기본 메서드, 자바 8
기본메서드, Default Method라고도 말하며 자바 8에서 새로 도입되었다.
기본 메서드를 사용하면 기존의 인터페이스를 수정하지 않고 기본 구현을 제공할 수 있다.
기본 메서드 특징
- 인터페이스 내에 구현된 메서드이다. 따라서 해당 인터페이스 구현한 클래스에서 기본 메서드 재정의 하지 않아도 된다.
- 기존의 인터페이스를 수정하지 않고도 새로운 메서드 추가 가능하다.
- 클래스에서 오버라이딩 가능하다. 따라서 클래스에서 기본구현을 변경할 수도 있다.
- Obejct 클래스가 제공하는 hashCode같은 다른 기본 클래스들 사용불가능하다.
기본 메서드 사용법
- 인터페이스 내에 구현
interface MyInterface {
void someMethod();
default void defaultMethod() {
System.out.println("기본 메서드");
}
}
과거 자바 8 이전의 인터페이스
추상클래스를 통해 각 구현체에서 편의 제공을 위해 필요한 메서드만 구현할려고 아래와 같이 구현했었다.
자바 8 이후의 인터페이스에서의 기본 메서드
자바 8 이후에서는 아래와 같이 추상클래스 없이 직접적으로 default를 통해 메서드를 구현할 수 있다
주의사항
- default method를 구현할 때 다른 개발자들이 어떻게 사용할지 고민해야한다. 만약 그러한 과정이 없다면 NullPointerException과 같은 오류가 발생할 수 있다
- 따라서 의도한대로 사용하게 하고 싶으면 문서화를 잘해야한다
주석을 사용하되, Javadoc형식으로 작성하면 좋다
인터페이스의 static 메서드, 자바 8
해당 인터페이스를 구현한 모든 인스턴스, 해당 타입에 관련되어 있는 유틸리티 메서드를 제공하고 싶다면 static method로 구현가능하다.
인터페이스 이름을 통해 직접 호출할수 있다. 왜냐면 static 메서드는 구현체의 일부가 아니라서 구현체 클래스에 속하는것이 아니라 인터페이스에 속한다. 따라서 따로 이 메서드를 오버라이딩하거나 구현할 필요가 없다.
예시는 다음과 같다.
MyInterface.java
public interface MyInterface extends InterfaceA, InterfaceB{
void methodA();
void methodB();
public static void staticMethod(){
System.out.println("staticMethod호출");
}
}
MyClass.java
public class MyClass implements MyInterface {
@Override
public void methodA() {
System.out.println("methodA가 호출되었다");
}
@Override
public void methodB(){ //구현
System.out.println("methodB가 호출되었다");
}
}
static 메서드은 staticMethod()는 구현체 클래스에 속하는것이 아니라 인터페이스의 일부이므로 MyClass에서 구현할 필요가 없다
Main.java
public class Main {
public static void main(String args[]) {
MyInterface myInterface = new MyClass();
MyInterface.staticMethod();
}
}
//출력문: staticMethod호출
위에 default, static 메서드의 등장으로 의미가 불투명해진 추상클래스?
자바 8이후로도 2개의 다른점이 있기때문에 추상클래스는 계속 사용될것이다.
자바 8기준으로 추상클래스와 인터페이스는 인스턴스화 하는것은 불가능하며, 구현부가 있는 메서드와 없는
메서드가질 수 있다는 점에서 유사하다. 하지만
인터페이스에서 모든 변수는 기본적으로 public static final 이며, default,static 메서드를 제외한 메서드는 public abstarct인 반면
추상클래스는 static 이나 final이 아닌 필드를 지정할 수 있고, public, protected, private접근제어자를 사용하는 메서드를 가질 수 있다
추상클래스와, 인터페이스의 적절한 사용 케이스
추상클래스
- 관련성이 높은 클래스 간에 코드를 공유하고 싶은 경우
- public이외의 접근 제어자 사용이 필요한 경우
인터페이스
- 서로 관련성이 없는 클래스들이 인터페이스를 구현하게 되는 경우에 사용
- 다중 상속을 허용하고 싶은 경우
인터페이스의 private 메서드, 자바 9
java 8에서 default method와 static method 추가가 되었다.
이후 java 9에서는 인터페이스에 추가적으로 private method와 private static method가 추가되었다.
사용예시
MyInterface.java
public interface MyInterface extends InterfaceA, InterfaceB{
void methodA();
void methodB();
private void privateMethod() {
System.out.println("privateMethod호출");
}
//인터페이스 내에서 기본메서드로 private메서드호출
default void staticMethod(){
System.out.println("staticMethod호출");
privateMethod();
}
}
Main.java
public class Main {
public static void main(String args[]) {
MyInterface myInterface = new MyClass();
myInterface.staticMethod();
}
}
출력문
추가 이유
- 특정 기능을 처리하는 내부 method인데 인터페이스는 public 접근 제어자를 써야하기때문에 외부에 계속 공개되었다
- interface를 구현하는 다른 interface혹은 class가 특정 메서드에 대해서 액세스 하거나 상속할 필요가 없는 경우가 있다
prviate 메서드 4가지 규칙
- private 메서드는 구현부를 가져야만 한다
- 오직 인터페이스 내부에서만 사용가능하다
- private static 메서드는 다른 static 또는 static이 아닌 메소드에서 사용할 수 있다
- private 메서드는다른 private 메서드에서 사용할 수 없다
->이를 통해 java9부터는 인터페이스에 대한 캡슐화를 유지할 수 있게 되었다
참고
유튜브 생활코딩 - 인터페이스 문법과 개념(1,2,3)
https://www.youtube.com/watch?v=Yv5Uw_vS3Uo
https://five-cosmos-fb9.notion.site/4b0cf3f6ff7549adb2951e27519fc0e6
'자바(Java)' 카테고리의 다른 글
[자바] 자바 멀티쓰레드 프로그래밍 (0) | 2023.09.21 |
---|---|
[자바] 자바 예외처리 (0) | 2023.09.14 |
[자바] 자바 패키지(package) (0) | 2023.08.28 |
[자바]자바 상속, 다이나믹&더블 메소드 디스패치 (0) | 2023.08.21 |
[자바] 자바 클래스 (0) | 2023.08.14 |