본문 바로가기
Java

Java - 인터페이스

by MoonGa 2023. 4. 1.

인터페이스 작성 문법

  • 인터페이스 이름은 무조건 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