Java

9. 인터페이스

문정훈 2022. 2. 6. 17:30
더보기

인터페이스 목차

1. 인터페이스 정리

  1) 상수필드, 추상메소드, 디폴드 메소드, 정적 메소드 선언
  2) 구현클래스 작성
  3) 다중인터페이스
  4) 인터페이스 상속 계층 일 때
  5) 디폴트 메소드 제대로 이해하자
  6) 인터페이스 확장

2. 중첩인터페이스

1. 인터페이스 정리

1) 상수필드, 추상메소드, 디폴드 메소드, 정적 메소드 선언

public interface InterfaceA {
    /*public static final*/ int VALUE= 10; //상수 필드
    /*public abstract*/ void func1 (); //추상 메소드
    /*public*/ default void func2() {}; //디폴트 메소드
    /*public*/ static void func3() {} //wjdwjr apthem 
    
}

자바의 인터페이스에서 선언할 수 있는 형태는 위와 같이 4가지이다.

주석 문을 달아놓은것은 인터페이스에서 int VALUE라고 선언한것은 public static final int VALUE와 동일한 것이다.

즉 상수의 역할을 하게 된다 .

나머지 3가지 메소드에 대해서도 마찬가지이다. 

인터페이스에서는 상수 필드, 추상 메소드, 디폴트 메소드, 정저 메소드 4가지가 선언이 가능하며 위와 깉아 주석문을 지우고 선언하더라도 주석문이 포함된 필드 또는 메소드가 된다. 

 

● 상수 필드

인터페이스는 일종의 객체 사용 설명서이다. 따라서 런타임 시에 데잍를 저장하는 필드를 가지지 않으며 고정된 값인 상수 필드만을 필드로 허락한다. 

상수 값은 반드시 초기 값을 대입해야한다. 

 

● 추상 메소드

인터페이스는 추상 메소드를 가지며 이것의 실제 구현 부는 인터페이스를 implements하는 클래스에서 구현하게 된다. 

인터페이스를 상속하는 클래스는 반드시 추상 메소드를 재정의 해야한다. 

 

● 디폴트 메소드

디폴트 메소드는 그 구현부가 인터페이스에 선언된 메소드이며 이는 인터페이스를 상속하는 모든 클래스에서 기본적으로 가지게 되는 메소드가 된다. 

인터페이스르 상속하는 클래스에서 디폴트 메소드를 재정의 하지 않아도 되며 재정의 하지 않는다면 인터페이스에서 선언한 메소드의 실행부가 실행되며, 만약 디폴트 메소드를 재정의한다면 재정의된 메소드가 호출된다. 

 

디폴트 메소드가 필요한 이유를 자세히 설명하면, 

100개의 클래스가 하나의 A라는 인터페이스를 상속한다고 해보자, 이때 인터페이스의 업그레이드 또는 기능 추가 또는 수정이란 이유로 인터페이스에 새로운 메소드인 abstract 메소드가 추가 된다고 해보자.

그럼 100개의 클래스에서 새로 추가되는 추상 메소드를 일일이 다 정의해야한다. 

이는 매우 비효율적이다.

A라는 인터페이스에 추가되는 메소드로 추상 메소드가 아닌 디폴트 메소드를 추가한다면 100개의 메소드는 인터페이스의 디폴트 메소드를 새롭게 가지게 되는 것이다. 

 

● 정적 메소드 

자바 8부터 정적 메소드가 도입되었는데 디폴트 메소드와 달리 인터페이스를 상속하는 객체 없이 인터페이스만으로 호출이 가능한 메소드이다. 

 

 

2) 구현 클래스 작성 

위 1) 번 글에서 인터페이스에서 선언되는 4가지 필트 또는 메소드의 형태를 정리했다. 

인터페이스를 상속하는 클래스의 작성 방법은 아래와 같다. 

pubilc class Classa implements InterfaceA {
    @Override
    public void func1() {
    
    }
    
    @Override
    public default void func2() {
    	
    }
}

interface InterfaceA {
    int VALUE =10;
    void func1();
    default func2();
    static func3();
}

func1()의 같은 경우 인터페이스에서 접근 제한자가 없으니 default 접근 제한자가 아닌가? 라는 생각을 할 수 있다.

인터페이스에서는 1)에서 설명한 것과 같이 func1은 public abstract라는 키워드가 없어도 이것이 있는 형태의 메소드로 간주한다.

인터페이스의 func2와 func3 역시 접근 제한자가 public으로 간주한다. 

 

 

3) 다중 인터페이스

자바에서는 다중 상속을 지원하지 않지만 다중 인터페이스는 가능하다. 

public class ClassA implements 인터페이스A, 인터페이스B, ... {}

즉 위와 같이 다중 인터페이스가 가능하다. 

다중 인터페이스에서 구현 클래스는 다중 인터페이스의 모든 추상메소드를 실체
메소드로 구현해야하며 각 인터페이스 타입에 구현 클래스 객체를 할당하면 해당 인터페이스 타입의 메소드만 실행이 가능하다. 

public class MainClass {
	public static void main(String ar[]) {
    	InterfaceA ia = new ClassA();
        ia.func1();
        ia.func2();//불가능
    }
}

class ClassA implements InterfaceA, InterfaceB {
	@Override
    public void func1() {
    
    }
    
    @Override
    pubilc void func2() {
    
    }
}

interface InterfaceA {
	void func1();
}

interface InterfaceB {
	void func2();
}

위 예시와 같이 ia.func2()는 인터페이스 타입 InterfaceA의 메소드가 아니므로 실행이 불가능하다. 

 

 

4) 인터페이스 상속 계층 일 때

인터페이스는 1개 이상의 인터페이스를 상속 받을 수 있다. 
예를 들어 인터페이스C가 인터페이스A, 인터페이스B를 두 개 상속받고 있다고 가정해 보자
그리고 인터페이스C를 구현하는 구현 클래스가 있다.
구현 클래스는 부모인터페이스까지 A,B,C모든 추상메소드를 재정의 해야한다.
인터페이스 타입A인 변수에 구현 객체를 생성하면 인터페이스A의 추상 메소드만 호출할 수 있다.
인터페이스 타입B인 변수에 구현 객체를 생성하면 인터페이스B의 추상 메소드만 호출할 수 있다.
인터페이스 타입C인 변수에 구현 객체를 생성하면 인터페이스A,B,C의 추상 메소드를 호출할 수 있다.

 

 

 

5) 디폴트 메소드 제대로 이해해자

기존에 인터페이스가 존재하고 그 인터페이스를 구현한 여러 개의 구현 클래스가 있다고 해보자.
이런 상황에서 인터페이스에 추상메소드를 추가하게 되면 모든 구현 클래스를 재 수정해야하는 일이 생긴다.
그래서 특정 구현 클래스에서 인터페이스의 메소드를 재정의해서 사용해야할 일이 있을 경우 
인터페이스에 디폴트 메소드를 선언한다. 
디폴드 메소드는 모든 구현 클래스에 존재한다고 생각하면 된다.
특정 구현 클래스에서 그 디폴트 메소드를 재정의하여 사용하면 된다.

 

 

6) 인터페이스 확장

public interface ParentInterface {
	void method();
    default void method2() {}
}

 

경우1) 

public interface ChildInterface1 extends ParentInterface {
	void method3();
}
ChildInterface1 ci1 = new ChildInterface1() {
    @Override
    public void method1() {}
    
    @Override
    public void method3() {}
}

ci1.method1();
ci1.method2(); // ParentInterface의 method2()가 호출된다.
ci1.method3();

 

 

경우2) 

public interface ChildInterface2 extends ParentInterface {
    @Override
    default void method2() {}
}
ChildInterface2 ci2 = new ChildInterface2() {
    @Override
    public void method1() {}
}

ci2.method1();
ci2.method2(); // ChildInterface2의 재정의 메소드가 호출된다.

인터페이스A가 인터페이스 B를 상속하는데 인터페이스A에서 인터페이스B의 default 메소드를 재정의할 수 있다. 

 

 

경우3)

pubilc interface ChildInterface3 extends ParentInterface {
    @Override
    public void method2();
}
ChildInterface3 ci3 = new ChildInterface3 () {
    @Override
    public void func1() {}
    
    @Override
    public void func2() {}
}

ci3.method1();
ci3.method2();

이 경우는 method2는 부모 인터페이스의 디폴트 메소드인데 자식 인터페이스에서 부모의 디폴트 메소드르 abstract 메소드로 재정의할 수 있다.

따라서 자식 인터페이스를 구현하는 클래스에서는 abstract func2를 재정의(실제 구현)하여 사용하면 된다. 


 

 

2. 중첩 인터페이스 

public class Exam1{
	public static void main(String[] ar) {
	Button button=new Button();
	A a=new A();
	button.setClick(a);
	}
}

class Button{
	interface Click{
		public abstract void onClick();
	}
	
	Click click;
	
	public void setClick(Click click)
	{
		this.click=click;
	}
	
	public void toch() 
	{
		click.onClick();
	}
}

class A implements Button.Click{
	@Override
	public void onClick()
	{
		
	}
}

 

중첩 인터페이스란 클래스 내부에 선언된 클래스의 맴버인 인터페이스를 말한다. 

해다 클래스와 긴밀한 관계를 가지는 구현 클래스를 만들기 위해 간간히 중첩 인터페이스를 사용한다. 

UI 프로그래밍에서 이벤트 처리를 할 목적으로 많이 활용 된다. 

 

 

 

'Java' 카테고리의 다른 글

11. 자바 예외 처리(실행 예외, 예외 처리 코드, 사용자 정의 예외)  (0) 2022.02.16
10. 중첩 클래스  (0) 2022.02.06
8. 상속  (0) 2022.02.06
7. 클래스 탐구  (0) 2022.01.20
6. 클래스 정리3 : 패키지와 imoprt  (0) 2022.01.20