[Java] 인터페이스 02. default, static, 다형성

김세림·2024년 4월 26일

Java

목록 보기
17/24
post-thumbnail

인터페이스 02. default, static, 다형성


default method

default 메소드란?

  • 추상 메소드의 기본적인 구현을 제공하는 메서드이며, 블럭이 존재한다.
  • default 메서드의 접근 제어자는 public이며 생략 가능하다.
  • 이미 구현되어있는 메소드로 추상메소드가 아니라서 오버라이딩이 불필요하다.

예제

public class Main implements A {

    @Override 
    public void a() { //interface의 추상메소드이므로 오버라이딩 필수
        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");
    }
}

Static method

static 메소드란?

static 은 이전에 인스턴스 멤버랑 클래스 멤버할때 나왔던 개념으로 객체 생성없이 바로 호출이 가능한 메서드이다.
클래스의 static 메서드와 여기 인터페이스의 메서드의 사용방법은 동일하다고 생각하면 된다.

예제

public class Main implements A {
	...
    public static void main(String[] args) {
        // static 메서드 aaa() 호출
        A.aaa();
    }
}

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

다향성

인터페이스의 타입변환

인터페이스의 타입변환도 이전 클래스의 타입변환과 매우 유사하다.

자동 타입변환

인터페이스 변수 = 구현객체; 는 자동으로 캐스팅없이도 변환이 일어난다.

강제 타입변환

구현객체타입 변수 = (구현객체타입) 인터페이스 변수;
로 구현된 클래스를 인터페이스에 넣었던 것을 다시 구현객체로 되돌리는 경우 캐스팅이 필요하다.

두가지에 대한 예제

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

       // A 인터페이스에 구현체 B(클래스) 대입
       A a1 = new B(); // 자동 타입변환
       a1.a();
       // a1.b(); // a타입이기 때문에 a()메소드만 있기 때문에 불가능하다. 

       B b = (B) a1; //강제타입변환
       b.a();
       b.b(); // 강제 타입변환으로 b타입이 되었기 때문에 사용 가능
       System.out.println();

       // A 인터페이스에 구현체 B를 상속받은 C 대입
       A a2 = new C();
       a2.a();
       //a2.b(); 
       //a2.c(); //이 또한 a타입이므로 해당 b,c 메소드는 불가능

       C c = (C) a2;
       c.a();
       c.b(); 
       c.c(); // 강제 타입변환으로 b,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()");
   }
}

인터페이스 다형성

이는 문자로 설명하면 헷갈리기때문에 코드를 보며 얘기해보도록 하겠다.

Tv 부모 추상 class

public abstract class Tv {

   private String company; // 티비 회사
   private int channel = 1; // 현재 채널 상태
   private int volume = 0;  // 현재 볼륨 상태
   private boolean power = false; // 현재 전원 상태

   public Tv(String company) {
       this.company = company;
   }

   public void displayPower(String company, boolean power) {
       if(power) {
           System.out.println(company + " Tv 전원이 켜졌습니다.");
       } else {
           System.out.println(company + " Tv 전원이 종료되었습니다.");
       }
   }

   public void displayChannel(int channel) {
       System.out.println("현재 채널은 " + channel);
   }

   public void displayVolume(int volume) {
       System.out.println("현재 볼륨은 " + volume);
   }

   public String getCompany() {
       return company;
   }

   public int getChannel() {
       return channel;
   }

   public int getVolume() {
       return volume;
   }

   public boolean isPower() {
       return power;
   }

   public void setChannel(int channel) {
       this.channel = Math.max(channel, 0);
   }

   public void setVolume(int volume) {
       this.volume = Math.max(volume, 0);
   }

   public void setPower(boolean power) {
       this.power = power;
   }
}

위 코드를 간략히 설명하면 tv라는 class는 samsung과 lg의 부모 클래스이며, 기본값은 private으로 캡슐화 해놓았고, 이를 gettersetter로 받고 저장할 수 있도록 해놓았다.
또한 생성자는 company를 받아 본인의 company변수에 저장하도록 하였으며, 생성자, getter, setter를 제외한 메소드는 3가지가 있다.
전원, 채널, 볼륨의 상태를 나타내는 메소드이다.

리모콘 인터페이스

public interface MultiRemoteController {

   void turnOnOff();
   void channelUp();
   void channelDown();
   void volumeUp();
   void volumeDown();

   // 매개변수와 반환타입 다형성 확인 메서드
   default MultiRemoteController getTV(Tv tv) {
       if(tv instanceof SamsungTv) {
           return (SamsungTv) tv;
       } else if(tv instanceof LgTv){
           return (LgTv) tv;
       } else {
           throw new NullPointerException("일치하는 Tv 없음");
       }
   }

}

위 코드를 간략히 설명하자면 MultiRemoteController 인터페이스로, 전원을 키고 끄는 메소드, 채널 올리고, 내리는 메소드, 볼륨 올리고, 내리는 메소드는 추상메소드로 구성되어있으며,
매개변수와 반환타입 다형성을 확인하는 instanceof를 사용중인 default 메소드로 이루어져있다.

Tv를 상속받고 리모콘 인터페이스의 구현체인 SamsungTv

lg도 같은 기능을 하므로 lgtv는 생략하겠다.

public class SamsungTv extends Tv implements MultiRemoteController{

   public SamsungTv(String company) {
       super(company);
   }

   @Override
   public void turnOnOff() {
       setPower(!isPower());
       displayPower(getCompany(), isPower());
   }

   @Override
   public void channelUp() {
       setChannel(getChannel() + 1);
       displayChannel(getChannel());
   }

   @Override
   public void channelDown() {
       setChannel(getChannel() - 1);
       displayChannel(getChannel());
   }

   @Override
   public void volumeUp() {
       setVolume(getVolume() + 1);
       displayVolume(getVolume());
   }

   @Override
   public void volumeDown() {
       setVolume(getVolume() - 1);
       displayVolume(getVolume());
   }
}

위 코드를 간략히 설명하자면 리모콘 인터페이스의 구현체로써 추상메소드들을 오버라이딩하여 사용하였으며, tv클래스의 자식클래스이므로 생성자는 company를 받아 본인의 부모클래스인 tv클래스에 저장한다.

Main 클래스(test용)

main클래스는 코드안에 주석으로 설명하겠다.

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

       // LG TV 구현체를 조작
       MultiRemoteController mrc = new LgTv("LG");
       mrc.turnOnOff();
       mrc.volumeUp();
       mrc.channelDown();
       mrc.channelUp();
       mrc.turnOnOff(); //해당 메소드들은 lgtv객체에서만 진행됨.

       // 조작 대상을 Samsung TV로 교체
       System.out.println("\n<Samsung TV로 교체>");
       mrc = new SamsungTv("Samsung");
       //새로운 객체가 생성된 것 = 값은 default로 초기화
       mrc.turnOnOff();
       mrc.channelUp();
       mrc.volumeDown();
       mrc.volumeUp();
       mrc.turnOnOff();

       // 매개변수, 반환타입 다형성 체크
       System.out.println("\n<매개변수, 반환타입 다형성 체크>");

       MultiRemoteController samsung = mrc.getTV(new SamsungTv("Samsung")); 
       //getTv안에 들어가야하는 매개변수는 Tv 클래스타입인데 
       //이를 상속받은 samsungtv 클래스가 다형성 개념으로 들어갔다.
       samsung.turnOnOff();

       SamsungTv samsungTv = (SamsungTv) samsung;
       //강제 타입변환으로 인터페이스 타입이었던 samsung을 SamsungTV 타입으로 변환하였다.
       samsungTv.turnOnOff();
   }
}

이렇게 인터페이스도 매개변수와 반환타입에서 다형성이 적용될 수 있다.

0개의 댓글