본문 바로가기

Java

12 - 2장 인터페이스

1. 인터페이스의 정의와 특징

 

 - 내부의 모든 필드가 public static final로 정의

 - static과 default 메서드 이외의 모든 메서드는 public abstract로 정의 

 - interface 키워드 사용하여 선언

 

 - 인터페이스 구조 

interface 인터페이스명 {
	public static final 자료형 필드명 = 깂;
    public abstract 리턴 타입 메서드명();
}
interface A {
	public static final int a = 3;
    public abstract void abc();
}

- 제어자를 명시적으로 적어 주지 않으면 컴파일러가 자동으로 각각의 제어자 삽입

  -> 메서드명 뒤에 중괄호가 없는데도 오류가 발생하지 않으므로  abstract가 자동으로 붙음

  -> static : 클래스명으로 바로 접근 가능

  -> final : 값이 입력된 후 다시 값을 입력할 수 없음

System.out.println(A.a); //클래스명이나 인터페이스명으로 접근가능(Static의 특징)
A.a=4; //값변경 불가능 (fianl 특징) 오류발생

 

2. 인터페이스의 상속

 

 - 클래스가 클래스를 상속할 때 extends 키워드 사용

 - 클래스가 인터페이스를 상속할 때 implements 키워드 사용

 - 다중 상속 가능 

 -1개의 클래스가 여러 개의 인터페이스를 상속할 때 쉼표(,)로 구분해 나열

클래스명 implements 인터페이스명, ..., 인터페이스명 {
	//내용
}

  - 클래스에서 다중상속을 할 수 없는 이유

  -> 두 부모 클래스에 동일한 이름의 필드 또는 메서드가 존재할 때 이를 내려받으면 충돌이 발생 (ambiquous error)

 

  - But 인터페이스에서는 모든 필드가 public static final로 정의돼 있어 실제 데이터값은 각각의 인터페이스 내부에 존재(저장 공간이 분리)해 공간상 겹치지 않음

 - 메서드 또한 모두 미완성이여서 자식 클래스 내부에서 완성해 사용

 

 - 클래스와 인터페이스를 동시에 상속하는 구조 

클래스명 extends 클래스명 implements 인터페이스명, ..., 인터페이스명 {
	//내용
}
package Interface;

interface A {}
interface B {}

//단일 인터페이스 상속
class C implements A {

}

//다중 인터페이스 상속
class D implements A,B {
	
}

//클래스와 인터페이스를 한 번에 상속
class E extends C implements A,B {
	
}
public class Interface1 {
	public static void main(String[] args) {
		
	}
}

 

 1) 클래스가 클래스를 상속할 때는 extends 

클래스 extends 클래스 {
	//...
}

 2) 클래스가 인터페이스를 상속할 때는 implements

클래스 implments 인터페이스 {
	//...
}

  - '클래스 A가 인터페이스 B를 상속했다.' = ' 클래스 A가 인터페이스 B를 구현했다'

  - 인터페이스 내의 모든 메서드는 추상 메서드이므로 자식 클래스는 온전히 이들 추상메서드를 구현 

 

 3) 인터페이스가 인터페이스를 상속할 때는 extends 

인터페이스 extends 인터페이스 {
	//...
}

 4) 인터페이스는 클래스를 상속할 수 없음

  - 클래스 내부에는 완성된 메서드가 존재 

  - 인터페이스는 내부에 추상 메서드만 포함할 수 있으므로 만일 인터페이스가 클래스를 상속한다면 상속과 동시에 오류 발생

 

주의점 1. 자식 클래스는 반드시 미완성 메서드를 완성시켜 줘야 문법적 오류를 피할 수 있음

interface A {
	public abstract void abc(); //미완성 메서드
}

class B implements A {
	public void abc() { // 완성 메서드
    }
}

 

주의점 2. 자식 클래스의 구현 메서드는 public만 가능 

  - 오버라이딩을 수행할 때 접근 지정자는 반드시 부모 메서드의 접근 지정자보다 접근 범위가 같거나 커야함

interface A {
	void abc(); //컴파일러가 자동으로 public abstract 제어자 추가
}

class B implements A {
	void abc() { //default 접근 지정자를 가지는 메서드로 오버라이딩 -> 접근범위가 좁아져 오류 발생
    }
}

 

3. 인터페이스 타입의 객체 생성 방법

 

- 인터페이스도 추상 메서드를 포함하고 있으므로 객체를 직접 생성할 수 없음

 

1) 자식 클래스를 직접 정의해 인터페이스 객체 생성

 

package Interface;

interface A{
	int a = 3;
	void abc();
}

class B implements A {
	public void abc() {
		System.out.println("방법 1. 자식 클래스 생성자로 객체 생성");
	}
}
public class Interface11 {
	public static void main(String[] args) {
		//객체 생성
		A b1 = new B();
		A b2 = new B();
		
		//메서드 호출
		b1.abc();
		b2.abc();
	}
}

 

 2) 익명 이너클래스를 활용해 인터페이스 객체 생성

package Interface;

interface A{
	int a = 3;
	void abc();
}

public class Interface11 {
	public static void main(String[] args) {
		//객체 생성
		A a1 = new A() {
			public void abc() {
				System.out.println("방법 2. 익명 이너 클래스를 이용한 객체 생성");
			}
		};
		
		A a2 = new A() {
			public void abc() {
				System.out.println("방법 2. 익명 이너 클래스를 이용한 객체 생성");
			}
		};
		
		//메서드 호출
		a1.abc();
		a2.abc();
		
	}
}

 

4. 인터페이스의 필요성 

 

 - 인터페이스 = 입출력의 호환성 

 - ex) 그래픽 드라이버 

 A사의 그래픽 카드와 B사의 그래픽 카드는 서로 다른 하드웨어 구조를 띠고 있음 

 

  1) 인터페이스 사용 X

  - A 사의 그래픽 카드를 활용한 애플리케이션을 작성한 후 그래픽 카드를 B사 제품으로 바꾸면 애플리케이션을 수정해야함

 

 2) 인터페이스 사용

 - 애플리케이션에서 인터페이스를 활용해 프로그램을 작성, 각 그래픽 회사들은 이 인터페이스를 구현한 클래스를 생성

 - 어떤 그래픽 회사이든 동일한 인터페이스를 상속해 드라이버를 제작하므로 모든 드라이버에는 동일한 메서드가 존재

 - 각 그래픽 드라이버가 인터페이스를 구현했으므로 그저 그 메서들 가져다 쓰면 되는 것

 

5. 디폴트 메서드와 정적 메서드 

 

 - 자바 8 등장 후 인터페이스의 기능 추가 

 

1) 인터페이스 내에 완성된 메서드인 디폴트(default)메서드가 포함 

 

 - 디폴트 메서드

interface 인터페이스명 {
	public default 리턴 타입 메서드명() {
    	//메서드 내용
    }
}

 - 디폴트 메서드 앞에 접근 지정자 public을 생략해도 컴파일러가 자동으로 삽입 

 

 - ex) 인터페이스 A를 클래스 100개에서 상속 

   - 인터페이스 내에 메서드를 1개 더 추가하면 이전에 만들어 사용하던 모든 자식 클래스에서 오류 발생 

    (새롭게 추가된 메서드를 구현하지 않았기 때문)

 

 - 디폴트 메서드 즉. 인터페이스 내부에 완성된 메서드를 삽입하면 문제 해결

 - 디폴트 메서드는 완성된 메서드이므로 자식 클래스는 이 메서드를 반드시 오버라이딩할 의무가 없음

 

package Interface;

interface A {
	void abc();
	default void bcd() {
		System.out.println("A 인터페이스의 bcd()");
	}
}

class B implements A {
	public void abc() { // 추상 메서드 구현
		System.out.println("B 클래스의 abc()");
	}
}

class C implements A {
	public void abc() { //추상 메서드 구현
		System.out.println("C 클래스의 abc()");
	}
	public void bcd() { // 인터페이스 A의 디폴트 메서드까지 오버라이딩
		System.out.println("C 클래스의 bcd()");
	}
}
public class DefaultMethod {
	public static void main(String[] args) {
		//객체 생성
		A a1 = new B();
		A a2 = new C();
		
		//메서드 호출 
		a1.abc();
		a1.bcd();
		a2.abc();
		a2.bcd();
	}

}

 - 디폴트 메서드는 일반 메서드 처럼 자식 클래스에서 오버라이딩해 사용 가능 

 

 - 자식 클래스에서 부모 인터페이스의 디폴트 메서드 호출 방법

부모 인터페이스명 super. 디폴트 메서드명

- 디폴트 메서드가 인터페이스 내부에 속하는 일반 메서드처럼 동작한다고 했으므로 자식 클래스에서 부모 인터페이스 내부의 디폴트 메서드도 호출 가능

- 인터페이스는 다중 상속이 되므로 어떤 부모 인터페이스 내부의 메서드를 호출하라는 소리인지 구분할 필요가 있음

package Interface;

interface A {
	default void abc() {
		System.out.println("A 인터페이스의 abc()");
	}
}

class B implements A {
	public void abc() {
		A.super.abc(); //부모 인터페이스 A의 abc() 메서드호출
		System.out.println("B 클래스의 abc()");
	}
}

public class DefaultMethod {
	public static void main(String[] args) {
		//객체 생성
		B b = new B();
		
		//메서드 호출
		b.abc(); //B 객체의 abc()를 호출할 때 A 인터페이스의 abc() 메서드가 먼저 호출됨
	}
	
	
}

 

2) Static 메서드를 포함할 수 있다.

 

 - 클래스 내부의 정적 메서드와 동일한 기능

 - 객체를 생성하지 않고 '인터페이스명.정적 메서드명' 방식으로 바로 호출 가능

package Interface;

interface A{
	static void abc() {
		System.out.println("A 인터페이스의 정적 메서드 abc()");
	}
}

public class DefaultMethod {
	public static void main(String[] args) {
		//정적 메서드 호출
		A.abc();
	}
	
}

'Java' 카테고리의 다른 글

13 - 2 장 익명 이너 클래스  (0) 2023.06.05
13 -1 장 이너 클래스  (0) 2023.06.04
12-1장 추상 클래스  (0) 2023.06.02
11-2장 abstract 제어자  (0) 2023.06.02
11-1장 final 제어자  (0) 2023.06.02