본문 바로가기

Programming/자바

자바 재정리 - 인터페이스

인터페이스의 특징

인터페이스 : 객체의 사용 방법 정의 (객체 사용 설명서)

 

1. 개발 코드와 객체의 통신 접점 

=> 개발 코드가 인터페이스 메소드 호출하고, 인터페이스는 객체 메소드 호출 

 

2. 다형성

여러 객체들과 사용 가능 => 객체에 따라 실행 내용, 리턴값 다양화 (코드 변경 없이)

 

 

 

 

  인터페이스 선언

.java 소스파일로 작성 -> 컴파일러 통해 .class로 컴파일됨 => 클래스와 동일 이름 불가

 

 

  • 인터페이스 선언
public interface Example{

    //상수
    int pi = 3.14;
    
    //추상 메소드
    public void cal();
    
    //디폴트 메소드
    default void print(int number){
    	if (number<10){
            System.out.println("10 미만");
        }
    }
    
    //정적 메소드
    static void print2(){
        System.out.println("안녕하세요");
    }

}

 public 접근제한자 => 다른 패키지에서도 사용 가능하도록 (생략해도 컴파일 과정에서 자동 반영)

인터페이스는 객체로 생성할 수 없으므로 생성자 가질 수 없음 => 상수, 메소드로만 구성됨

 

 

구성 멤버 :

 

1. 상수 필드

객체 사용 설명서인터페이스는 데이터를 저장할 수 없으므로 런타임 시 데이터를 저장할 수 있는 인스턴스, 정적 필드는 선언 불가

상수 선언 시 초기값 반드시 대입

public, static, final 생략해도 컴파일 과정에서 자동 반영

 

 

2. 추상 메소드★

중괄호 없이 객체의 메소드만 설명 (메소드명, 리턴타입, 매개변수만 표시)

실제 실행부는 구현 객체가 가짐

public abstract 생략해도 컴파일 과정에서 자동 반영

 

 

3. 디폴트 메소드

클래스의 인스턴스 메소드 형태

public 생략해도 컴파일 과정에서 자동 반영

 

 

4. 정적 메소드

클래스의 정적 메소드 형태

객체 없이 인터페이스만으로 호출 

public 생략해도 컴파일 과정에서 자동 반영

 

 

 

 

인터페이스 구현
  • 구현 클래스 

: 인터페이스의 구현객체(인터페이스의 추상메소드를 실체화한 메소드를 가진 객체)를 생성하는 클래스

 

public class 구현클래스명 implements 인터페이스명{
    ...
    추상 메소드의 실체 메소드 선언
    ...
}

 

=> 인터페이스의 모든 메소드는 public (public보다 낮은 접근 제한 불가)

 

 

  • 익명 구현 객체

구현 객체와 달리 소스파일 작성하지 않아도 되므로 효율적

단기 이벤트, 임시 작업 시 사용

추상메소드의 실체 메소드 작성 필수

필드, 메소드 추가로 선언 가능 but 익명 객체 안에서만 사용 (인터페이스 변수로 접근 불가)

 

인터페이스 변수 = new 인터페이스(){실체 메소드};

remoteControl rc = new RemoteControl(){~~};

 

 

  • 다중 구현 클래스

: 2개 이상의 인터페이스가 객체의 메소드 호출하려면 객체는 해당 인터페이스들 모두 구현

하나라도 실체 메소드가 선언되지 않으면 추상 클래스로 선언됨

 

public 구현 클래스명 implements 인터페이스1, 인터페이스2 {
    인터페이스1 추상메소드의 실체메소드 선언
    인터페이스2 추상메소드의 실체메소드 선언
}

 

 

  • ex
public class SmartTV implements RemoteControl, Searchable{ //다중구현

    private int volume;
    
    //Searchable 실체 메소드
    @Override
    public void search(String url) {
        System.out.println(url+"을 검색합니다.");
    }

    //RemoteControl 실체 메소드
    @Override
    public void turnOn() {
        System.out.println("스마트TV를 켭니다.");
    }

    @Override
    public void turnOff() {
        System.out.println("스마트TV를 끕니다.");

    }

    @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);
    }

}

 

 

 

 

인터페이스 사용

인터페이스로 구현 객체 사용 => 인터페이스 변수(참조타입) 선언 후 구현 객체 대입

 

 

  • 추상 메소드 

 

RemoteControl rc = new Television();
rc.turnOn();
rc.turnOff();

 

 

  • 디폴트 메소드

구현 클래스에서 재정의(필요 시) 후 예제에서 사용

 

RemoteControl rc = new Television();
rc.setMute(true);

 

 

  • 정적 메소드

객체 생성 없이 인터페이스로 바로 호출 가능

 

RemoteControl.change();

 

 

 

 

인터페이스 예제
  •  
  • 인터페이스
public interface RemoteControl {
    //상수
    public final int MAX_VOLUME=10; 
    public final int MIN_VOLUME=0;
    
    //추상 메소드: 객체의 메소드 설명
    public void turnOn();  //컴파일시 자동으로 abstract로 인식 (생략 ok) 
    public void turnOff();
    public void setVolume(int volume);
    
    //디폴트 메소드: 객체 구현과 관련 X 인스턴스 메소드 
    default void setMute(boolean mute) {
        if (mute) {
            System.out.println("무음 처리합니다");
        }else {
            System.out.println("무음 해체합니다");
        }
    }
    
    //정적 메소드: 인터페이스 자체에서 수행되는 메소드
    static void changeBattery() {
        System.out.println("건전지를 교환합니다");
    }
}

 

 

  • 구현 클래스
public class Television implements RemoteControl{ //추상메소드 구현 必 => add unimplemented methods

    private int volume;
    
    //추상메소드 구현
    @Override
    public void turnOn() {
        System.out.println("TV를 켭니다.");
    }

    @Override
    public void turnOff() {
        System.out.println("TV를 끕니다.");
        
    }

    @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;
    
    @Override
    public void turnOn() {
        System.out.println("오디오를 켭니다.");
    }

    @Override
    public void turnOff() {
        System.out.println("오디오를 끕니다.");
        
    }

    @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("현재 오디오 볼륨 : "+this.volume);
    }
}
 

 

  • 인터페이스 사용 예제
public class RemoteControlEx1 {

    public static void main(String[] args) {
        RemoteControl rc; //인터페이스 변수 선언
        
        rc=new Television(); //인터페이스 구현 객체 대입 => 다형성
        rc.turnOn();
        rc.setVolume(5);
        rc.setMute(true);
        rc.setMute(false);
        rc.turnOff();
        
        rc=new Audio(); //인터페이스 구현 객체 대입 => 다형성
        rc.turnOn();
        rc.setVolume(20);
        rc.setMute(true);
        rc.setMute(false);
        rc.turnOff();
    }

}​

 

 

 

 

타입 변환 & 다형성

인터페이스 타입에 어떤 구현 객체를 대입하는지에 따라 실행 결과가 달라짐 (다형성)

= 코드 변경 없이 구현 객체만 교체해 프로그램 실행 결과를 다양하게 만들 수 있음

 

//InterfaceEx ie = new A();
InterfaceEx ie = new B(); //A->B 객체 교체

//메소드 수정할 필요 없음
ie.method1();
ie.method2();

 

 

cf. 다형성

상속 : 같은 종류의 하위 클래스 생성 

인터페이스 : 사용 방법이 동일한 클래스 생성

 

 

  • 자동타입변환

인터페이스 변수 = 구현 객체;

 

public interface A {}

class B implements A {} //B 클래스가 A 인터페이스 구현
class C extends B {} //C 클래스가 B 클래스 상속

B b = new B();
C c = new C();

A a1 = b; //자동 타입 변환 //다형성
A a2 = c; //자동 타입 변환 //다형성

 

 

  • 필드의 다형성

필드 선언, 구현 객체 대입 후 다른 구현 객체로 교체

 

 

  • 필드 => 인터페이스 배열로 관리
public class Car {

  //Tire 필드 선언, HankookTire 객체 대입
  Tire[] tires = {
    new HankookTire{},
    new HankookTire{},
    new HankookTire{},
    new HankookTire{},
  };

  void run(){
    for (Tire tire : tires){
      tire.roll();
    }
  }

}


public class CarEx{

  public static void main(String[] args) {
    Car myCar = new Car();
    myCar.run();
    myCar.tires[0] = new KumhoTire; //HankookTire -> KumhoTire 객체 교체 //자동타입변환
    myCar.tires[1] = new KumhoTire; //
    myCar.run();
  }

}

//
한국타이어
한국타이어
한국타이어
한국타이어


금호타이어
금호타이어
한국타이어
한국타이어

 

 

  • 매개변수의 다형성

메소드의 매개변수 타입이 인터페이스 => 구현 객체 모두 매개값으로 사용 가능

 

 

  •  
public class Driver {
	public void drive(Vehicle vehicle){ //매개변수: Vehicle 인터페이스
            vehicle.run();
    }
}

 

public interface Vehicle {
    //메서드
    public void run();
}​

 

public class Taxi implements Vehicle {
    @Override
    public void run() {
        System.out.println("택시가 달립니다.");
    }
}​

 

public class Bus implements Vehicle {   
    @Override
    public void run() {
        System.out.println("버스가 달립니다.");
    }
    
    public void checkFare(){
    	System.out.println("승차요금 체크합니다");
    }
}
 
 
public class DriverEx1 {

    public static void main(String[] args) {
        Driver chulsu = new Driver();
        
        Taxi taxi = new Taxi();        
        Bus bus = new Bus();
        
        chulsu.Drive(bus); //매개변수의 다형성 (인터페이스 구현 객체 대입함)
        chulsu.Drive(taxi); //
    }
}
 
//
버스가 달립니다
택시가 달립니다
 
 
 
  • 강제타입변환

: 구현 객체 -> 인터페이스 변환된 상태에서 구현 객체로 재변환

 

 

  •  
public class VehicleEx2 {

    public static void main(String[] args) {
        Vehicle vehicle = new Bus();  //자동타입변환
        vehicle.run(); //오버라이드한 run 실행
        
        Bus bus=(Bus)vehicle;  //강제형변환
        bus.run();
        bus.checkFare(); //Bus 클래스에만 존재하는 메소드
    }
    
}
 

//
버스가 달립니다.
버스가 달립니다.
승차요금 체크합니다.

 

 

  • instanceof (객체 타입 확인)

강제타입변환 가능한 객체인지 확인

 

 

  • instanceof 미적용한 오류 예제
public class Driver {

    void Drive(Vehicle vehicle) {  
        Bus bus=(Bus)vehicle; //Bus로 강제타입변환 (Bus 타입이었다가 매개변수에서 Vehicle로 변환된 객체 한정)
        bus.checkFare();
        vehicle.run();
    }
    
}​

 

public class DriverEx1 {

    public static void main(String[] args) {
        Driver chulsu = new Driver();

        Taxi taxi = new Taxi();
        Bus bus = new Bus();

        chulsu.Drive(bus);
        chulsu.Drive(taxi); //오류 //Bus로 강제타입변환되지 않음
    }
}

 

 

=> 해결

  • instanceof 사용
public class Driver {
    
    void Drive(Vehicle vehicle) {  
        if (vehicle instanceof Bus) { //Bus->Vehicle인지 확인
           Bus bus=(Bus)vehicle; //강제형변환
           bus.checkFare();
        }
        vehicle.run();
    }
}

 

 

 

 

인터페이스 상속

인터페이스도 다른 인터페이스 상속 가능

다중 상속 허용됨

하위 인터페이스의 구현 클래스는 상위 인터페이스의 추상메소드에 대한 실체 메소드 가져야 함

 

public interface 하위 인터페이스 extends 상위 인터페이스1, 상위 인터페이스2 {}

 

//상위 인터페이스
public interface ParentA {
	public void parentMethod1();
}

public interface ParentB {
	public void parentMethod2();
}

//하위 인터페이스
public interface Child extends ParentA, ParentB {
	public void childMethod();
}

//하위 인터페이스 구현
public class Implementation implements Child {

	public void parentMethod1(){ //상위 인터페이스 실체메소드
    	System.out.println("parent1");
    }
    
	public void parentMethod2(){ //상위 인터페이스 실체메소드
    	System.out.println("parent2");    
    }
    
	public void childMethod(){ //하위 인터페이스 실체메소드
    	System.out.println("child");    
    }

}

//인터페이스 사용
public class Ex {
	public static void main(String[] args){
    	Implementation im = new Implementation(); //하위 인터페이스 구현 객체
    
        ParentA p1 = im; //상위 인터페이스로 타입 변환
        p1.parentMethod1(); //상위 인터페이스 메소드만 호출 가능

        Child ch = im; //하위 인터페이스로 타입 변환
        ch.parentMethod1(); //상하위 메소드 모두 호출 가능
        ch.parentMethod2();
        ch.childMethod();
    
}

 

 

 

디폴트 메소드 & 인터페이스 확장

디폴트 메소드 : 인터페이스에서 선언된 인스턴스 메소드, 구현 객체 통해 사용

=> 구현 클래스에서 실체메소드 작성할 필요 X / 필요하면 오버라이딩해서 재정의 가능

 

 

  • 디폴트 메소드 있는 인터페이스 상속

1. 단순 상속

 

2. 재정의, 실행 내용 변경

 

3. 디폴트메소드를 추상메소드로 재선언

public interface ParentInterface{
	public void method1(); //추상메소드
        public default void method2(){..} //디폴트 메소드
}

public interface ChildInterface extends ParentInterface {
	public void method2(); //추상메소드로 재선언
        public void method3();
}

 

=> 구현 클래스는 method 1~3의 실체메소드 모두 가져야 함

 

 

 

 

'Programming > 자바' 카테고리의 다른 글

자바 재정리 - 예외 처리  (0) 2022.08.26
자바 재정리 - 중첩 클래스, 중첩 인터페이스  (0) 2022.08.26
자바 재정리 - 상속  (0) 2022.08.23
자바 재정리 - 클래스  (0) 2022.08.11
자바 재정리 - 참조  (0) 2022.08.05