2022-10-12 다형성2

JYR00·2022년 10월 12일
0

TIL

목록 보기
24/60

다형성

자식 객체가 부모 객체의 옷을 입고 부모행세. 그러나 자식 객체가 가지고 있는 데이터를 출력한다.

  • 자식 -> 부모 : 자동 타입변환 // 부모->자식: 강제 타입변환

  • 오버라이딩을 통해 다형성 구현

매개 변수의 다형성

매개변수가 클래스 타입일 경우

해당 클래스의 객체 대입이 원칙이나 자식 객체 대입하는 것도 허용

  • 자동 타입변환
  • 매개변수의 다형성

매개변수 다형성 예제

Driver, DriverEx, Taxi, Bus, Vehicle

Vehicle

public class Vehicle {
    public void run(){
        System.out.println("차량이 달립니다.");
    }
}

Bus

public class Bus extends Vehicle{
    @Override
    public void run() {
        System.out.println("버스가 달립니다.");
    }
}

Taxi

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

Driver

public class Driver {
    public void drive(Vehicle vehicle){
        vehicle.run();
    }
}

DriverEx

import package1.B;
import package2.D;

public class DriverEx {
    public static void main(String[] args) {
        Driver driver = new Driver();

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

		driver.drive(new Vehicle());
        driver.drive(bus);
        driver.drive(taxi);
    }
}

강제 타입 변환(casting)

  • 부모 타입을 자식 타입으로 변환하는 것.

  • 조건: 자식 타입을 부모 타입으로 자동 변환 후, 다시 자식 타입으로 변환할 때

  • 자식 타입에 선언된 필드와 메서드를 다시 사용해야 할 경우 필요하다.

  • instace of사용하여 변환 가능한지 확인을 먼저 해야 한다. 안하면 오류남.

  • 원래 자신이었던 것만 가능.


좌항(부모타입) 우항(원본타입)
boolean해서 true나와야 변환이 가능하다.

강제타입변환 예제

parent2 child2 child2ex

Parent2

public class Parent2 {
    public String field1;

    public void method1(){
        System.out.println("부모 메서드1 실행");
    }

    public void method2(){
        System.out.println("부모 메서드2 실행");
    }
}

Child2

public class Child2 extends Parent2{
    public String field2;

    public void method3(){
        System.out.println("자식 메서드3 실행");
    }
}

Child2Ex

import package2.C;

public class Child2Ex {
    public static void main(String[] args) {
//        자동 타입 변환
//        부모 클래스 타입의 변수에 자식 클래스 타입의 객체를 대입하면 부모 클래스 타입의 멤버만 사용이 가능하다.
//        (알맹이는 자식 클래스 타입의 객체)
        Parent2 parent2 = new Child2();
        parent2.field1 = "data1";
        parent2.method1();
        parent2.method2();

//        parent2.field2 = "데이터2"; //error 부모 흉내를 내고 있기 때문에 본인이 가지고 있는 것을 사용하지못한다.
//        parent2.method3(); //error

        System.out.println("\n=====자식 클래스 타입의 변수에 자식 클래스 타입의 객체 대입=====\n"); // 상속받은 모든 걸 사용할 수 있다.
        Child2 child2 = new Child2();
        child2.field1 = "데이터1";
        child2.field2 = "데이터2";
        child2.method1();
        child2.method2();
        child2.method3();

        System.out.println("\n------다시 자식 클래스 타입으로 돌아갈 때------\n");

        Child2 child21 = new Child2();
        child21.field1 = "Parent2에서 상속받은 멤버 변수"; //상속
        child21.field2 = "전용으로 가지고 있는 멤버 변수";
        System.out.println("객체 child21의 field1 출력 : " + child21.field1);
        System.out.println("객체 child21의 field2 출력 : " + child21.field2);
        System.out.println("객체 child21의 method1 실행 : ");
        child21.method1(); //상속
        System.out.println("객체 child21의 method2 실행 : ");
        child21.method2(); //상속
        System.out.println("객체 child21의 method3 실행 : ");
        child21.method3();

        System.out.println("\n부모 객체로 자동 타입 변환 \n");

        Parent2 parent21 = child21;
        System.out.println("객체 parent21의 field1 출력" + parent21.field1);
//        System.out.println("객체 parent21의 field1 출력" + parent21.field2); //에러난다.

        System.out.println("객체 parent21의 field1 출력 : " + parent21.field1);
//        System.out.println("객체 parent21의 field2 출력 : " + parent21.field2); // 에러 난다. 자식 클래스 전용
        System.out.println("객체 parent21의 method1 실행 : ");
        parent21.method1(); //상속
        System.out.println("객체 parent21의 method2 실행 : ");
        parent21.method2(); //상속
        System.out.println("객체 parent21의 method3 실행 : "); //자식 클래스 타입의 전용이기 때문에 사용안된다.
//        parent21.method3(); 에러

        System.out.println("\n다시 자식 클래스 타입으로 변환\n");

//        자식 클래스 타입의 변수에 부모 클래스 타입의 객체를 대입하면 오류 발생
//        원본 객체를 자식 클래스 타입의 변수로 타입 변환 시 해당 객체의 모든 멤버를 가지고 있는지
//        알 수 없기 때문에 강제 타입 변환을 해야 한다.
        Child2 child22 = (Child2)parent21; //무조건 앞에 () 씌워야
//        child22.field1 = "Parent2에서 상속받은 멤버 변수"; //상속
//        child22.field2 = "전용으로 가지고 있는 멤버 변수";
        System.out.println("객체 child22의 field1 출력 : " + child22.field1);
        System.out.println("객체 child22의 field2 출력 : " + child22.field2);
        System.out.println("객체 child22의 method1 실행 : ");
        child22.method1();
        System.out.println("객체 child22의 method2 실행 : ");
        child22.method2();
        System.out.println("객체 child22의 method3 실행 : ");
        child22.method3();

        System.out.println("\n다시 자식 클래스 타입으로 변환되는 조건\n");
//      1. 원본이 자식 클래스 타입이어야 해당하는 자식 클래스 타입으로 변환이 가능.

//        원본이 부모 클래스 타입
//        Parent2 parent23 = new Parent2();
////        자식 클래스 타입의 변수 선언
//        Child2 child23;
////        자식 클래스 타입의 변수에 부모 클래스 타입의 객체를 대입
////        문법 상의 오류는 없으나 원본이 자식 클래스 타입의 객체가 아니기 때문에 런타임 에러(실행하는 순간 에러)가 발생
//        child23 = (Child2) parent23; //여기서 오류 child23 = (Child2) parent23;
////        자식 클래스 타입의 객체의 멤버를 사용
//        child23.method3();

        Parent2 parent24 = new Child2(); //알맹이는 child2
        castMethod1(parent24); //성공
        castMethod2(parent24); //성공

        Parent2 parent25 = new Parent2();
        castMethod1(parent25); //25로 변환되지 않음
        castMethod2(parent25); //오류 발생

    }
    public static void castMethod1(Parent2 parent){
//        instanceof 연산자를 사용하면 현재의 객체가 지정한 타입의 객체인지 확인이 가능함. 반드시 사용하자.
        if(parent instanceof Child2){
            Child2 child = (Child2) parent;
            System.out.println("castMethod1 - Child2로 변환 성공");
        }
        else{
            System.out.println("castMethod2 - Child2로 변환 되지 않음");
        }
    }

    public static void castMethod2(Parent2 parent){
//        원본 객체가 변환하려는 클래스 타입의 객체가 아닐 수 있기 때문에 오류가 발생할 수 있음.
        Child2 child = (Child2) parent;
        System.out.println("castMethod1 - Child2로 변환 성공");
    }
}


추상클래스 복습(3가지 기억해라)

  • 1) 추상 클래스란 추상 메서드를 가지고 있는 클래스
  • 사용하는 이유는 규격을 강제하기 위해
  • 2) 추상 클래스는 객체 생성안된다. 몸체가 없기 때문에. new안된다.
  • 부모 역할만 가능
  • 3) 이름을 통일하거나 설계 규격 만들고자 할 때 사용.
  • 상속받을 때 오버라이딩 사용해야 한다.

✨인터페이스

  • 개발 코드와 객체가 서로 통신하는 접점
  • 추상클래스 업그레이드판이라고 생각하면 된다. 규격 강제!!
  • 인터페이스를 구성하고 있는 모든 것이 추상메서드다. 일반 멤버와 일반 멤버 메서드는 하나도 없다. 전부 다 추상메서드로 이루어져 있다.

인터페이스 선언하기

  • 인터페이스 이름 - 자바 식별자 작성 규칙 따라
  • 선언
[public] interface 인터페이스명{...}

default 혹은 public을 주로 사용한다. 그냥 public붙여라..
{ ... }에 추상메서드 넣어라.

  • 인터페이스는 상수 필드만 선언 가능
  • 인터페이스에 선언된 필드는 모두 public static final이다. 자동적으로 붙기 때문에 생략가능
  • 상수명은 대문자. 다른 단어와 구성되어있을 때 언더바로 연결
  • 선언과 동시에 초기값 지정
    • static{}블록 작성 불가. - static{}으로 초기화불가

추상 메서드 선언

public abstract 생략하더라도 자동적으로 컴파일에 생긴다. 생략해도 된다.

디폴트 메서드 선언

정적 메서드 선언

인터페이스 구현

  • 추상 클래스 -> 객체 생성 불가 , 상속 전용 , 변수 생성 가능 //extends
  • 인터페이스 -> 객체 생성 불가 , 상속 전용 , 변수 생성 가능 // implements

=> 자식 클래스에게 상속을 받아 사용해야한다.

마지막 사용 단어를 제외하고는 거의 동일하다.

  • 추상메서드의 실체 메소드 작성 할 때 오버라이딩 규칙을 그대로 따르면 된다.

인터페이스 구현2

  • 상속 - 부모의 특성, 기능 물려받아 사용
  • 여러 부모에게 필요한 것들을 다 물려받음 => 다중상속

💖추상클래스는 클래스이기 때문에 단일 상속만 가능하고, 인터페이스는 다중 상속이 가능하다!!!💖

익명 구현 객체

인터페이스 변수명 = new 자식객체(){...}

다중 인터페이스 구현 클래스

SmartTelevision

public class SmartTelevision implements RemoteControl,Searchable{
    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);
    }

    @Override
    public void search(String url) {
        System.out.println(url + "을 검색합니다");
    }
}

RemoteControl.changeBattery();

setMute()

  • 일상 클래스의 정적메서드 -> 객체. 정적메서드명()하면 호출
  • 반드시 인터페이스명. 정적메서드(); 해야 호출 가능하다.

다형성

  • 하나의 타입에 여러 가지 객체를 대입해 다양한 실행 결과를 얻는 것.
  • 객체를 부품화시킬 수 있어 유지 보수에 용이하다.
    TireI HankookTire2 KumhoTire2 Car4 Car4Ex

타입변환과 다형성

타입변환과 다형성 예제

Car5 HankookTire2 KumhoTire2 Car4ex

Vehicle2 bus2 taxi2 driver2 Driver2EX

인터페이스 간 상속

  • 다중 상속이 가능하다. 구현체는 모든 추상메서드를 구현해야 한다.
    디즈니플러스, 넷플릭스

강제타입변환 예제

driverex2

   public static void main(String[] args) {
        System.out.println("각각 객체를 생성해서 실행");
        Bus2 bus2 = new Bus2();
        Taxi2 taxi2 = new Taxi2();
        
        bus2.run();
        taxi2.run();

        System.out.println("\n익명 객체를 통한 구현");
//        Vehicle2 vehicle2 = new Vehicle2(); 이거안됨
        Vehicle2 vehicle2 = new Vehicle2() {
            @Override
            public void run() {
                System.out.println("탈 것이 달립니다");
            }
        };
        vehicle2.run();
        System.out.println("\n부모 인터페이스 타입의 변수에 자식 객체를 대입");
        vehicle2 = bus2;
        vehicle2.run();
        vehicle2=taxi2;
        vehicle2.run();

        System.out.println("\n 인터페이스 변수를 매개변수로 사용시 ");
        Driver2 driver2 = new Driver2();
        driver2.drive(bus2);
        driver2.drive(taxi2);




        ///강제 타입변환 예제
        System.out.println("\n-----자동 타입변환, 강제 타입변환, instanceof------\n");

//        자동 타입 변환, 부모인 Vehicle2 인터페이스 타입의 변수에 자식인 Bus2 클래스 타입의 객체를 대입
        Vehicle2 vehicle21 = new Bus2();
        vehicle21.run();

//        데이터 타입이 다르므로 강제 타입 변환을 시도해야 함.
//        Bus2 bus21 = vehicle21;

//        강제 타입 변환의 조건이 원본이 자식 클래스 타입의 객체일 때 해당 클래스 타입으로 변환 시 가능
//        원본 클래스 객체 타입이 맞는지 확인을 하기 위해서는 instanceof 연산자를 사용해야 함

        Bus2 bus21 = (Bus2) vehicle21;
        bus21.run();

        Vehicle2 vehicle22 = new Bus2();
        vehicle22.run();

//        Taxi2 taxi22 = (Taxi2) vehicle22; //오류발생. instanceof로 확인해야.
//        taxi22.run();

        if(vehicle22 instanceof Taxi2){  //변경할 수 없다고 뜬다.
            Taxi2 taxi22 = (Taxi2) vehicle22;
            taxi22.run();
            System.out.println("정상적으로 Taxi2 클래스 타입으로 변경 했습니다.");
        }
        else {
            System.out.println("Taxi2 클래스 타입으로 변경할 수 없습니다.");
        }
    }
}

인터페이스 상수, 정적멤버메서드, 추상메서드, 디폴트메서드 예제

RemoteControl, Audio, Television, Searchable, SmartTelevition, RemoteControlEx

인터페이스

InterfaceA ImplC InterfaceB InterfaceC

InterfaceA

public interface InterfaceA {
    public void methodA();
}

InterfaceB

public interface InterfaceB {
    public void methodB();
}

InterfaceC

public interface InterfaceC extends InterfaceA,InterfaceB{
    public void methodC();

}

ImplC

public class ImplC implements InterfaceC{

    @Override
    public void methodA() {
        System.out.println("구현클래스 C / ImplementC - 메서드A 실행");
    }

    @Override
    public void methodB() {
        System.out.println("구현클래스 C / ImplementC - 메서드B 실행");
    }

    @Override
    public void methodC() {
        System.out.println("구현클래스 C / ImplementC - 메서드C 실행");
    }
}

ImplEx

public class ImplEx {
    public static void main(String[] args) {
        System.out.println("구현체 implC의 객체 impl은 모든 메서드 사용 가능");
        ImplC impl = new ImplC();

        impl.methodA();
        impl.methodB();
        impl.methodC();

        System.out.println("\nInterfaceA의 변수에 대입 시");
        InterfaceA ifA = impl;
        ifA.methodA();


        System.out.println("\nInterfaceB의 변수에 대입 시");
        InterfaceB ifB = impl;
        ifB.methodB(); //b만 있음


        System.out.println("\nInterfaceC의 변수에 대입 시");
        InterfaceC ifC = impl;
        ifC.methodC(); //3개가 다 있다. 할머니, 할아버지께 다 물려받음
        ifC.methodB();
        ifC.methodA();
    }
}




















0개의 댓글