[JAVA] 인터페이스

2024. 11. 25. 02:23·Programming Language/자바(JAVA)

인터페이스란?

두 장치를 연결하는 접속기

  • 만약 객체 A가 객체 B를 직접 사용한다면 객체 A의 소스 코드를 객체 B에서 C로 변경하는 작업 필요
  • 그러나 객체 A가 인터페이스의 메소드를 호출한다면 객체 B가 C로 변경된 것에는 신경쓸 필요 없음
  • 즉, 객체 A는 신경쓸 필요 없이 인터페이스만 고치면 된다.

인터페이스 선언 - interface

public interface 인터페이스명 {
    // public 상수 필드
    // public 추상 메소드(구현 클래스에서 구현해야 함)
    // public 디폴트 메소드(default)
    // public 정적 메소드
    // private 메소드
    // private 정적 메소드(static)
}

구현 클래스 선언 - implements

public class B implements 인터페이스명 {...}

변수 선언과 구현 객체 대입

  • 인터페이스도 하나의 타입이므로 변수의 타입으로 사용할 수 있다.
  • 인터페이스는 참조 타입에 속하므로 인터페이스 변수에는 객체를 참조하고 있지 않다는 뜻으로 null 대입 가능하다.
  • 인터페이스를 통해 구현 객체를 사용하려면 인터페이스 변수에 구현 객체의 번지를 대입해야 한다.
public interface RemoteControl {
    // public 추상 메소드
    public void turnOn();
}

public class Television implements RemoteControl {
    @Override
    public void turnOn() {
        System.out.println("TV를 켭니다.");

    }
}

public class Audio implements RemoteControl {
    @Override
    public void turnOn() {
        System.out.println("Audio를 켭니다.");
    }
}


public class RemoteControlExample {
    public static void main(String[] args) {
        // 변수 타입으로 인터페이스 선언
        RemoteControl rc;

        // rc 변수(인터페이스)에 Television 객체 대입
        rc = new Television();
        rc.turnOn();        // TV를 켭니다.

        // rc 변수에 Audio 객체를 대입(교체)
        rc = new Audio();
        rc.turnOn();        // Audio를 켭니다.
    }
}

상수 필드 - static final

  • 인터페이스에 선언된 필드는 모두 public static final 특성을 갖기 때문에 public static final을 생략하더라도 자동적으로 컴파일 과정에서 붙게 된다.
  • 상수명은 대문자로하되, 서로 다운 단어는 _(언더바)로 연결
  • 상수 필드는 객체 없이 클래스로 접근해서 읽을 수 있음
public interface 인터페이스이름 {
    int MAX_VOLUME = 10;
}

추상 메소드 - abstract

  • 인터페이스에서는 public abstract를 생략해도 컴파일 과정에서 자동으로 붙게 됨
    • [public abstract] 리턴타입 메소드명(매개변수, ...);
  • 구현 클래스에서 추상 메소드를 재정의할 때, 인터페이스의 추상 메소드는 기본적으로 public 접근 제한을 갖기 때문에 public보다 더 낮은 접근 제한으로 재정의할 수 없다

디폴트 메소드 - default

  • 인터페이스에 완전한 실행 코드를 가진 메소드
  • 추상 메소드와 다르게 실행부가 구현되어 있음
    • [public] default 리턴타입 메소드명(매개변수, ...) {...}
  • 구현 객체가 필요한 메소드
    • 구현 객체를 인터페이스 변수에 대입하고 나서 호출
  • 디폴트 메소드를 재정의할 때는 public 접근 제한자를 반드시 붙여야 하고, default 키워드를 생략

정적 메소드 - static

  • 구현 객체 없이 인터페이스만으로 접근하여 호출 가능
  • [public | private] static 리턴타입 메소드명(매개변수, ...) {...}
  • 정적 메소드의 실행부에는 상수 필드를 제외한 추상 메소드, 디폴트 메소드, private 메소드 등을 호출할 수 없다.
    • 구현 객체가 필요한 인스턴스 메소드이기 때문이다.
public interface RemoteControl {
    // 상수 필드
    int MAX_VOLUME = 10;
    int MIN_VOLUME = 0;

    // 추상 메소드
    void turnOn();
    void turnOff();
    void setVolume(int volume);

    // 디폴트 인스턴스 메소드
    default void setMute(boolean mute) {
        if(mute) {
            System.out.println("무음 처리합니다.");
            setVolume(MIN_VOLUME);
        } else {
            System.out.println("무음 해제합니다.");
        }
    }

    // 정적 메소드
    static void changeBattery() {
        System.out.println("리모콘 건전지를 교환합니다.");
    }
}

public class Television implements RemoteControl {
    // 필드
    private int volume;

    // turnOn() 추상 메소드 오버라이딩
    @Override
    public void turnOn() {
        System.out.println("TV를 켭니다.");
    }

    // turnOff() 추상 메소드 오버라이딩
    @Override
    public void turnOff() {
        System.out.println("TV를 끕니다.");
    }

    // setVolume() 추상 메소드 오버라이딩
    @Override
    public void setVolume(int volume) {
        if(volume > RemoteControl.MAX_VOLUME) {
            this.volume = RemoteControl.MAX_VOLUME;
        } else if(volume < RemoteControl.MIN_VOLUME) {
            this.volume = RemoteControl.MIN_VOLUME;
        } else {
            this.volume = volume;
        }
        System.out.println("현재 TV 볼륨: " + this.volume);
    }
}

public class Audio implements RemoteControl {
    // 필드
    private int volume;

    // turnOn() 추상 메소드 오버라이딩
    @Override
    public void turnOn() {
        System.out.println("Audio를 켭니다.");
    }

    // turnOff() 추상 메소드 오버라이딩
    @Override
    public void turnOff() {
        System.out.println("Audio를 끕니다.");
    }

    // setVolume() 추상 메소드 오버라이딩
    @Override
    public void setVolume(int volume) {
        if(volume > RemoteControl.MAX_VOLUME) {
            this.volume = RemoteControl.MAX_VOLUME;
        } else if(volume < RemoteControl.MIN_VOLUME) {
            this.volume = RemoteControl.MIN_VOLUME;
        } else {
            this.volume = volume;
        }
        System.out.println("현재 Audio 볼륨: " + this.volume);
    }

    // 필드
    privat int memoryVolume;

    // 디폴트 메소드 재정의
    @Override
    public void setMute(boolean mute) {
        if(mute) {
            this.memoryVolume = this.volume;
            setVolume(RemoteControl.MIN_VOLUME);
        } else {
            setVolume(this.memoryVolume);    // 원래 볼륨으로 복원
        }
    }
}


public class RemoteControlExample {
    public static void main(String[] args) {
        // 인터페이스 변수 선언
        RemoteControl rc;

        // Television 객체를 생성하고 인터페이스 변수에 대입
        rc = new Television();
        rc.turnOn();
        rc.setVolume(5);

        // 디폴트 메소드 호출
        rc.setMute(true);
        rc.setMute(false);

        // Audio 객체를 생성하고 인터페이스 변수에 대입
        rc = new Audio();
        rc.turnOn();
        rc.setVolume(5);

        // 디폴트 메소드 호출
        rc.setMute(true);
        rc.setMute(false);

        // ★ 구현 객체 없이 인터페이스 명으로 정적 메소드 호출 ★
        RemoteControl.changeBattery();
    }
}

private 메소드

  • private 메소드
    • 디폴트 메소드 안에서만 호출 가능
  • private static 메소드
    • 디폴트 메소드와 static 메소드에서 호출 가능
// static 메소드에서 private static 메소드 호출
static void staticMethod1() {
    staticCommon();
}

private static void staticCommon() {
    ...
}

다중 인터페이스

  • 구현 객체는 여러 개의 인터페이스 implements 할 수 있다.
    • public class 구현클래스명 implements 인터페이스A, 인터페이스B { //모든 추상 메소드 재정의 }
public interface RemoteControl {
    // 추상 메소드
    void turnOn();
    void turnOff();
}

public interface Searchable {
    // 추상 메소드
    void search(String url);
}

public class SmartTelevision implements RemoteControl, Searchable {
    // turnOn() 추상 메소드 오버라이딩
    @Override
    public void turnOn() {
        System.out.println("TV를 켭니다.");
    }

    // turnOff() 추상 메소드 오버라이딩
    @Override
    public void turnOff() {
        System.out.println("TV를 끕니다.");
    }

    // search() 추상 메소드 오버라이딩
    @Override
    public void search(String url) {
        System.out.println(url + "을 검색합니다.");
    }
}

public class MultiInterfaceImplExample {
    public static void main(String[] args) {
        // RemoteControl 인터페이스 변수 선언 및 구현 객체 대입
        RemoteControl rc = new SmartTelevision();
        // RemoteControl 인터페이스에 선언된 추상 메소드만 호출 가능
        rc.turnOn();
        rc.turnOff();

        // Searchable 인터페이스 변수 선언 및 구현 객체 대입
        Searchable searchable = new SmartTelevision();
        // Searchable 인터페이스에 선언된 추상 메소드만 호출 가능
        searchable.search("https://www.youtube.com");
    }
}

인터페이스 상속 - extends

  • 인터페이스도 다른 인터페이스 상속할 수 있음
  • 다중 상속 가능
    • 클래스는 단일 상속만 가능
  • public interface 자식인터페이스 extends 부모인터페이스1, 부모인터페이스2 {...}
  • 자식 인터페이스의 구현 클래스는 자식 인터페이스의 메소드뿐만 아니라 부모 인터페이스의 모든 추상 메소드를 재정의해야 한다.
    • 부모 인터페이스1
    • 부모 인터페이스2
      • 자식 인터페이스 -> 얘 구현 클래스는 자식, 부모1, 부모2 추상 메소드 모두 구현

타입 변환

  • 인터페이스 타입 변환은 인터페이스와 구현 클래스 간에 발생

자동 타입 변환

  • 인터페이스 변수 = 구현객체;
    • 구현 객체가 인터페이스 타입으로 자동 타입 변환

강제 타입 변환

  • 구현클래스 변수 = (구현클래스) 인터페이스변수;
  • RemoteControl로 자동 타입 변환된 Television 객체 rc
  • Television 객체에만 선언된 setTime(), record() 메소드를 사용하려면 다시 Television으로 강제 타입 변환을 해야 함

RemoteControl rc = new Television();
rc.turnOn();
rc.turnOff();
rc.setVolume(5);
tv.setTime(); // 불가능
tv.record(); // 불가능

// Television으로 강제 타입 변환
Television tv = (Television) rc;
tv.turnOn();
tv.turnOff();
tv.setVolume(5);
tv.setTime();
tv.record();

필드의 다형성

public class Car {
    // 필드로 인터페이스 선언하고 구현 객체 대입
    Tire tire1 = new HankookTire();
    Tire tire2 = new KumhoTire();
}

Car myCar = new Car();
myCar.tire1 = new KumhoTire(); // 구현 객체 변경 가능

매개변수의 다형성

  • 매개변수 타입으로 인터페이스로 선언하면 인자로 다양한 구현 객체 대입 가능
    • 자동 타입 변환 성질 이용
public interface Vehicle {
    // 추상 메소드
    void run();
}

public class Driver {
    // ★ 구현 객체가 대입될 수 있도록 매개변수를 인터페이스 타입으로 선언 ★
    void drive(Vehicle vehicle) {    
        vehicle.run();                // 인터페이스의 추상 메소드 호출
    }
}

public class Bus implements Vehicle {
    // 추상 메소드 재정의
    @Override
    public void run() {
        System.out.println("버스가 달립니다.");
    }
}

public class Taxi implements Vehicle {
    // 추상 메소드 재정의
    @Override
    public void run() {
        System.out.println("택시가 달립니다.");
    }
}

public class DriverExample {
    public static void main(String[] args) {
        // Driver 객체 생성
        Driver driver = new Driver();

        // Vehicle 구현 객체 생성
        Bus bus = new Bus();
        Taxi taxi = new Taxi();

        // ★ 매개값으로 구현 객체 대입 ★
        driver.drive(bus);
        driver.drive(taxi);
    }
}

객체 타입 확인 - instanceof

  • 상속에서 객체 타입을 위해 instanceof 연산자를 사용했듯이 인터페이스에서도 사용할 수 있다.
  • 만약 매개값이 특정 구현 객체일 경우에만 강제 타입 변환을 하고 싶다면 instanceif 연산자를 사용해 매개값의 타입 검사
public void method(Vehicle vehicle) {
    // vehicle이 Vehicle 타입의 Bus 객체일 경우 Bus 타입으로 강제 타입 변환
    if(vehicle instanceof Bus) {
        Bus bus = (Bus) vehicle;
        // bus 변수 사용
    }
}

// Java 12부터는 instanceof 연산의 결과가 true일 경우 우측 타입 변수를 사용할 수 있기 때문에 강제 타입 변환이 필요 없다.
if(vehicle instanceof Bus bus) {
    // bus 변수 사용
}

봉인된 인터페이스

  • Java 15부터는 무분별한 자식 인터페이스 생성을 방지하기 위해 봉인된 인터페이스 사용 가능
// Interface A의 자식 인터페이스는 InterfaceB만 가능
public sealed interface InterfaceA permits InterfaceB {...}

// InterfaceB는 non-sealed 키워드로 선언하거나, sealed 키워드를 사용해 또 다른 봉인 인터페이스로 선언
public non-sealed interface InterfaceB extends InterfaceA {...}
// InterfaceB는 non-sealed이기 때문에 상속 가능
public interface InterfaceC extends InterfaceB {...}

'Programming Language > 자바(JAVA)' 카테고리의 다른 글

[JAVA] java.base 모듈 - 각종 클래스, 리플렉션, 어노테이션  (1) 2024.11.26
[JAVA] 중첩 클래스, 중첩 인터페이스, 익명 객체  (0) 2024.11.25
[JAVA] 상속  (0) 2024.11.25
[JAVA] 클래스 - 접근 제어자, final, static  (0) 2024.11.24
[JAVA] 참조 타입 - 문자열, 배열  (3) 2024.11.21
'Programming Language/자바(JAVA)' 카테고리의 다른 글
  • [JAVA] java.base 모듈 - 각종 클래스, 리플렉션, 어노테이션
  • [JAVA] 중첩 클래스, 중첩 인터페이스, 익명 객체
  • [JAVA] 상속
  • [JAVA] 클래스 - 접근 제어자, final, static
토자맨
토자맨
  • 토자맨
    개발하는 토자맨
    토자맨
  • 전체
    오늘
    어제
    • 개발 공부
      • 코딩 테스트
        • 코드업 기초 100제
        • 백준
        • 99클럽
        • 자료구조
        • 알고리즘
      • Programming Language
        • 자바(JAVA)
      • Back-end
        • Spring
      • Front-end
        • html
        • css
      • DevOps
        • AWS
        • CI CD
        • Docker
        • 홈서버
        • Git
      • Computer Science
        • 자료구조
        • 알고리즘
        • 운영체제
        • OS,Network,DB,DesignPattern
      • 프로젝트
        • 웨이트 쇼핑몰
      • 공부 로드맵
        • 2학년 겨울방학
        • 3학년 2학기
        • 3학년 겨울방학
      • 일상
        • 기타 정보
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    백준 #dfs #11725번
    bfs #최단거리탐색 #프로그래머스
    티스토리챌린지
    dfs #백준
    ec2 멈춤 #ec2 터짐 #ec2 ssh 연결 끊김 #ec2 끊김
    프로그래머스 #dp
    git filter-repo
    백준 #bfs
    nvidia container toolkit #
    solid #객체지향설계원칙
    스프링핵심원리 #김영한 #의존관계자동주입 #의존관계 자동 주입
    백준 #이진탐색 #이분탐색
    백준 #dfs
    백준 #dfs #알고리즘
    오블완
    프로그래머스 #dfs
    99클럽 #코딩테스트 준비 #개발자 취업 #항해99 #til
    이진탐색 #이분탐색 #백준
    백준 #dp #동적계획법
    이진탐색 #이분탐색 #알고리즘
    백준 #아기상어2 #bfs
    dfs #알고리즘
    싱글톤 패턴 #싱글톤 컨테이너 #싱글톤 레지스트리 #싱글톤 객체 상태 #무상태 #stateless #유지상태 #staleful
    dp #백준 #동적계획법
    스프링 #spring #스프링 컨테이너 #스프링 컨텍스트
    nvidia-docker #docker cuda #docker gpu #엔비디아 도커
    피보나치 수 #백준 #dp
    git filter-branch #commit 수정 #commit
    bfs #백준
    bfs #프로그래머스
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
토자맨
[JAVA] 인터페이스
상단으로

티스토리툴바