인터페이스 작성 문법
- 인터페이스 이름은 무조건 Upper CamelCase(첫번째 글자만 대문자!!)
- 인터페이스도 확장자가 .java파일로 작성됨.
- 인터페이스의 모든 필드는 public static final로만 정의 가능(public static final 생략 가능, ex> 타입 상수이름 = 값, int a = 3;)
- 모든 메소드는 public abstract여야함.(public abstract 생략 가능, ex>타입 메서드이름(파라미터) = void ex();)
- 인터페이스내에서 메소드는 선언만 되어있기에, 추상클래스와 마찬가지로 new연산자로 인스턴스 생성 불가(특정 class implements 인터페이스명)
- 다중 상속 가능(클래스 상속-extends와 인터페이스 구현-implements 동시 가능)
인터페이스 일부 구현(추상 클래스)
- if, 클래스가 구현하는 인터페이스의 메서드 중 일부만 구현한다면 --> abstract를 붙여서 추상 클래스로 선언해야함.
- 인터페이스를 상속한 클래스에서 메서드 구현을 안한다면, 추상 메서드를 가진 추상 클래스가 되기에 abstract는 필수로 붙여줘야함.
interface Animal {
void walk();
void run();
void breed();
}
abstrct class Mammalia implements Animal {
public void run() {---}
public void walk() {----}
}
// 자식 클래스
class Lion extends Mammalia {
@Override
public void breed() {---}
}
인터페이스 자체 상속
- 인터페이스 자체 확장 시, extends를 통해서 다중 상속 가능(클래스 상속에 대해서는 다중 상속 불가)
인터페이스 상수 필드 상속 관계
- 클래스의 상속 --> 클래스 필드 멤버끼리 상속되어 덮어 씌워지지만, 인터페이스의 필드들은 모두 public static final로 상수이기에 서로 상속을 해도 독립적으로 운용됨.
interface Iflower {
int ex = 10; // public static final이 생략된 인터페이스 필드(상수)
}
interface IPlant extends Iflower {
int ex = 30; //상수
}
class Tulip implements IPlant {
int ex = 50; // 인스턴스 변수
}
public class Main {
public static void main(String[] args) {
// 클래스 타입 객체로 ex 멤버에 접근 --> 클래스 인스턴스 변수로 접근
Tulip t = new Tulip();
System.out.println(t.ex) // 50
// 인터페이스 타입 객체로 멤버에 접근 --> 인터페이스 static 상수로 접근
Iflower a = new Tulip();
System.out.println(a.ex); // 10(안좋은 방법)
System.out.println(Iflower.ex); // 10 - 클래스 static처럼 '인터페이스.멤버'로 접근
IPlant b = new Tulip();
System.out.println(b.ex); // 30(안좋은 방법)
System.out.println(IPlant.ex); // 30 - 클래스 static처럼 '인터페이스.멤버'로 접근
}
}
java 8 - 인터페이스 구현 메서드
- 인터페이스 메서드는 구현체를 가질 수 없지만, java 8부터 default method와 static method를 통해 구현 메서드 정의가능.
- 기존 인터페이스에 추상 메서드 추가 하면, 이 인터페이스를 구현하고 있는 모든 구현 클래스도 변경이 필요해지기에 추상 메서드 대신 default method를 새로 추가하여 해결 가능.
- 인터페이스에 static method 추가 가능 --> 인터페이스 명으로 직접 호출해야함. ex> 인터페이스명.static 메서드명();
인터페이스의 Default method
- default method는 구현부가 있어야함.
- 접근 제어자 = public(생략 가능)
- 자식 클래스에서 default 메서드를 오버라이딩해서 재정의 가능.
- 보통 인터페이스 구현 이후, 수정과정에서 인터페이스 모든 구현체에게 수정 없이 광역으로 함수를 만들어주고 싶을 때 사용됨. --> 대신 모든 구현체가 원하는 값을 return하게 보장하기 위해 @implSpec 자바 doc태그를 사용해서 문서화해줘야함.
- 인터페이스의 default method를 호출하기 위해선, 객체의 타입을 무조건 인터페이스 타입으로 업캐스팅 해줘야함!
default method 다중 상속 문제
- 다중 인터페이스들 간의 default method 충돌 - 같은 default method에 대해서 인터페이스를 구현한 클래스에서 default method를 오버라이딩하여 하나로 통합 해주기
- 인터페이스의 default method와 부모 클래스 메서드간의 충돌 --> 부모 클래스의 메서드가 상속되고, 디폴트 메서드는 무시됨 --> if, 인터페이스의 default method를 사용해야 한다면, 이 메서드를 오버라이딩하면됨.
interface A1 {
public void styleA();
// c1 클래스와 메서드 시그니처가 같은 default method
default public void styleSame() {
System.out.println("A1 인터페이스의 디폴트 메서드");
}
}
abstract class C1 {
// A1 인터페이스와 메서드 시그니처가 같은 인스턴스 메서드
public void styleSame() {
System.out.println("C1 클래스의 인스턴스 메서드");
}
}
// 메서드 시그니처가 같은 두 추상화들을 동시에 상속
class MultiClassInterface extends C1 implements A1 {
@Override
public void styleA() {--}
}
public class Main {
public static void main(String[] args) {
MultiClassInterface m1 = new MultiClassInterface();
m1.styleSame(); // "C1 클래스의 인스턴스 메서드" - 클래스의 메서드가 우선 적용.
// 인터페이스 타입으로 다운캐스팅해도, 클래스 인스턴스 메서드로 호출됨.
((A1) m1).styleSame(); "C1 클래스의 인스턴스 메서드"
}
}
// 인터페이스 default 메서드 사용을 원할 경우
class MultiClassInterface extends C1 implements A1 {
@Override
public void styleA() {--}
// 인터페이스의 default method 오버라이딩
public void styleSame() {
System.out.println("A1 인터페이스의 디폴트 메서드");
}
}
public class Main {
public static void main(String[] args) {
MultiClassInterface m1 = new MultiClassInterface();
m1.styleSame(); // "A1 클래스의 디폴트 메서드"
}
}
- default 메서드의 super --> 상위 클래스 상속, 상위 메서드 오버라이딩 했을 때 부모 메서드를 호출할 일이 생긴다면 super키워드를 토해 부모 메서드 호출가능. --> 인터페이스도 디폴트 메서드를 구현한 클래스에서 오버라이딩 했을 때, super를 통해 인터페이스의 원래 디폴트 메서드 호출 가능.(인터페이스명.super.디폴트메서드)
interface IPrint {
default void print() {
System.out.println("인터페이스의 디폴트 메서드");
}
}
class MyClass implements IPrint {
@Override
public void print() {
Iprint.super.print(); // 인터페이스의 super 메서드 호출
System.out.println("인터페이스의 디폴트 메서드 재정의 메서드");
}
}
public class Main {
public static void main(String[] args) {
MyClass cls = new MyClass();
cls.print();
}
}
//출력 결과
// 인터페이스의 디폴트 메서드
// 인터페이스의 디폴트 메서드 재정의 메서드
인터페이스의 static method
- 클래스가 가지고 있는 static method와 동일함.
- interface명.method로 사용
인터페이스의 private method
- java 9에 추가된 메서드
- private메서드도 구현부를 가져야함.
- private 메서드는 인터페이스 내부에서만 돌아가는 코드.(인터페이스를 구현한 클래스에서 사용 or 재정의 불가)
- 인터페이스 내부에서 private 메서드를 호출할 때, default 메서드 내부에서 호출해야함.(private static 키워드를 붙인 메서드는 static 메서드에서만 호출 가능)
'Java' 카테고리의 다른 글
Java - 배열 1 (0) | 2023.04.01 |
---|---|
Java - 팩토리 메소드 패턴, Java Reflection (0) | 2023.04.01 |
Java - 접근제한자 (0) | 2023.03.22 |
Java - final클래스, 불변객체 String (0) | 2023.03.22 |
Java - 추상 클래스 (0) | 2023.03.22 |