컴퓨터 프로그래밍/Java

[Java] 인터페이스

한33 2024. 7. 30. 10:46

인터페이스

상속 관계가 없는 다른 클래스들이 서로 동일한 행위 즉, 메서드를 구현해야할 때 인터페이스는 구현 클래스들의 동일한 사용 방법과 행위를 보장

 

선언

public interface 인터페이스명 {

}

 

구성

  • 모든 멤버 변수는 public static final ( 생략 가능 )
  • 모든 메서드는 public abstract ( 생략 가능 ( static, default 메서드 예외 ) )
  • 생략되는 제어자는 컴파일러가 자동으로 추가
public interface 인터페이스명 {
    public static final char A = 'A';
    static char B = 'B';
    final char C = 'C';
    char D = 'D';

    void turnOn(); // public abstract void turnOn();
}

 

turnOn() 메서드 처럼 추상 클래스마냥 뒤에 볼륨 {} 없이 그냥 선언만 한다.

 

구현

public class 클래스명 implements 인터페이스명 {
    // 추상 메서드 오버라이딩
    @Override
    public 리턴타입 메서드이름(매개변수, ...) {
        // 실행문
    }
}

 

  • implements 키워드를 이용해서 구현
  • 인터페이스의 추상 메서드는 반드시 오버라이딩 되어야함.
  • 만약 인터페이스의 추상 메서드를 일부만 구현해야 한다면 해당 클래스를 추상 클래스로 변경시켜준 후에 상속시켜서 다음에 남은 메서드를 구현하는 방법으로 넘길 수 있음

상속

  • 마찬가지로 extends 키워드를 사용해 상속시킴
  • 인터페이스는 클래스와는 다르게 다중 상속이 가능
public class Main extends D implements C {

    @Override
    public void a() {
        System.out.println("A");
    }

    @Override
    public void b() {
        System.out.println("B");
    }

    @Override
    void d() {
        super.d();
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.a();
        main.b();
        main.d();
    }
}

interface A {
    void a();
}

interface B {
    void b();
}

interface C extends A, B {
}

class D {
    void d() {
        System.out.println("D");
    }
}

 

Main 클래스는 D 로부터 상속받음.

D 를 보면 d 메서드가 있고 이는 "D" 를 출력함.

하지만 자식 클래스인 Main 에서  메서드 d 는 super.d(); 로 재선언 되어있지만 결국 이는 동일한 결과 출력

그리고 인터페이스 C 를 받음

인터페이스 C 는 A,B 로 부터 상속받음

인터페이스 A 는 인터페이스 메서드 a, 인터페이스 B 는 메서드 b 를 가지고 있음

메서드 a 와 b 는 각 각 "A", "B" 를 출력하는 걸로 Override 되어있음

결국 Main 함수의 생성자에서 인스턴스화 시킨다음 a,b,d 를 호출하면 A, B, D 를 출력한다.


default 메서드

추상 메서드의 기본적인 구현을 제공하는 메서드

  • 메서드 앞에 default 키워드를 붙이며 블럭{ }이 존재해야 함.
  • default 메서드 역시 접근 제어자가 public이며 생략이 가능.
  • 추상 메서드가 아니기 때문에 인터페이스의 구현체들에서 필수로 재정의 할 필요는 없음.
public class Main implements A {

    @Override
    public void a() {
        System.out.println("A");
    }


    public static void main(String[] args) {
        Main main = new Main();
        main.a();

        // 디폴트 메서드 재정의 없이 바로 사용가능합니다.
        main.aa();
    }
}

interface A {
    void a();
    default void aa() {
        System.out.println("AA");
    }
}

 

인터페이스 A 에서 aa 메서드 앞에 default 를 붙였고 그랬기 때문에 main 메서드에서 main.aa() 로 오버라이딩 없이 사용 가능

 

static 메서드

static 의 특성 그대로 인터페이스의 sattic 메서드 또한 객체 없이 호출이 가능

public class Main implements A {

    @Override
    public void a() {
        System.out.println("A");
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.a();
        main.aa();
        System.out.println();

        // static 메서드 aaa() 호출
        A.aaa();
    }
}

interface A {
    void a();
    default void aa() {
        System.out.println("AA");
    }
    static void aaa() {
        System.out.println("static method");
    }
}

 

인터페이스 A 에서 static 으로 선언된 aaa 메서드가 main 메서드에서 A.aaa 로 객체 선언 없이 바로 사용이 가능


다형성

타입 변환

public class Main {
    public static void main(String[] args) {

        // A 인터페이스에 구현체 B 대입
        A a1 = new B();
        a1.a();
        // a1.b(); // 불가능

        System.out.println("\nB 강제 타입변환");
        B b = (B) a1;
        b.a();
        b.b(); // 강제 타입변환으로 사용 가능
        System.out.println();

        // A 인터페이스에 구편체 B를 상속받은 C 대입
        A a2 = new C();
        a2.a();
        //a2.b(); // 불가능
        //a2.c(); // 불가능

        System.out.println("\nC 강제 타입변환");
        C c = (C) a2;
        c.a();
        c.b(); // 강제 타입변환으로 사용 가능
        c.c(); // 강제 타입변환으로 사용 가능


    }
}

interface A {
    void a();
}
class B implements A {
    @Override
    public void a() {
        System.out.println("B.a()");
    }

    public void b() {
        System.out.println("B.b()");
    }
}
class C extends B {
    public void c() {
        System.out.println("C.c()");
    }
}

 

C 는 B 를 자식 클래스이고 B 는 인터페이스 A 를 갖고있다.

그럼 C > B > A 순서

 

A a2 = new C() ; 로 자동 형 변환을 했기 때문에

a2 에서는 C 에 들어가 있는 메서드 c, B 에 들어가있는 메서드 b 는 사용할 수 없다.

 

사용하기 위해서 C c = (C) a2 ;

로 강제 형 변환을 한 것을 알 수 있다.

 

 

'컴퓨터 프로그래밍 > Java' 카테고리의 다른 글

[Java] Generic  (0) 2024.08.04
[Java] 예외처리  (0) 2024.07.30
[Java] 상속  (0) 2024.07.29
[Java] this와 this(), 접근 제어자, package와 import  (0) 2024.07.29
[Java] 생성자  (0) 2024.07.28