자바

[자바] 다형성

j9972 2022. 8. 6. 13:13
728x90
다형성 - 하나의 메소드나 클래스가 있을때 다양한 방법으로 동작하는 것을 의미한다

 

다형성의 쉬운 예제는 오버로딩이다. ( 같은 이름 동작 방법 )

class O {
    public void a(int param) {
        System.out.println(param);
    }
    public void a(String param) {
        System.out.println(param);
    }   
}

public class polyDemo {
    public static void main(String[] args) {
        O o = new O();
        o.a(10);
        o.a("ten");
    }
}

 

클래스와 다형성

class A {
    public String x() {
        return "x";
    }
}

class B extends A {
    // 오버라이딩 -> 부모클래스보다 우선순위가 높다
    public String x() { return "B.x"; }
    public String y() {
        return "y";
    }
}

public polyDemo {
    public static void main(String[] args) {
        A obj = new B(); // B의 인스턴트가 A의 형태를 한다 
        // obj의 데이터 타입은 A 이다
        obj.x(); 
        obj.y(); // 얘 때매 오류남
        // obj.x(); -> x가 아닌 B.x가 출력된다
    }
}

 

여기에서 알아야 할 것

1. 어떤 클래스를 인스턴스화 할때, 인스턴스를 담는 변수의 데이터 타입은 그 클래스(B)가 될수 있고, 부모클래스(A)가 될 수 있다 
효과 ) 인스턴스가 부모클래스인 A처럼 동작을 할 수 있다.
쓰는 이유) 오버라이딩하면 부모가 아닌 오버라이딩한 메소드가 있는 클래스의 메소드가 호출된다 ( B )

 

 

실전예제

부모클래스데이터타입 참주변수 = new 자식클래스데이터타입

 

abstract class Cal {
    int left, right
    public void setOprands(int left, int right) {
    ...
    }
}
    
    
public class CalDemo {
    public static void main(String[] args) {
        // 다형성 추가 x
        CalPlus c1 = new CalPlus();
        // 다형성 추가 o
        Cal c1 = new CalPlus();
        
        c1.setOprands(10,20);
        c1.run(); // sum, avg메소드
        
        // 다형성 추가x
        CalMinus c2 = new CalMinus();
        // 다형성 추 가 o
        Cal c1 = new CalMinus();
        
        c2.setOprands(10,20);
        c2.run();
    }
}


// 조금더 다형성 추가
abstract class Cal {
    int left, right
    public void setOprands(int left, int right) {
    ...
    }
}
    
    
public class CalDemo {
    public static void execute(Cal cal) {
        cal.run(); // 부모클래스의 sum, avg 메소드를 실행시켜준다
    }
    
    /*다형성 추가 x -> 코드 중복
    public static void execute(CalPlus cal) {
        cal.run(); // 부모클래스의 sum, avg 메소드를 실행시켜준다
    }
    public static void execute(CalMinus cal) {
        cal.run(); // 부모클래스의 sum, avg 메소드를 실행시켜준다
    }
    public static void main(String[] args) {
        CalPlus c1 = new CalPlus();
        CalMinus c1 = new CalMinus();
    }
    */

    public static void main(String[] args) {
        Cal c1 = new CalPlus();
        c1.setOprands(10,20);
        
        Cal c1 = new CalMinus();
        c2.setOprands(10,20);
        
        execute(c1);
        execute(c2);
    }
}

 

인터페이스와 다형성

기본 예시 코드

interface I {}
class C implements I {}
public class polyDemo {
    public static void main(String[] args) {
         I obj = new C();
    }
}

 

설명

클래스 C가 인스턴스화가 될때 데이터 타입이 I 가 될 수 있는 이유는 C가 I를 구현하기 때문이다.

 

new 예시

interface I2 {
    public String A();
}

interface I3 {
    public String B();
}

class D implements I2, I3 {
    public String A() {
        return "A";
    }
    public String B() {
        return "B";
    }
}

public class polyDemo {
    public static void main(String[] args) {
        D obj = new D(); // ( 모든 기능을 쓰고 싶다면 이렇게 해야함 )
        I2 objI2 = new D(); // 특정 기능만 사용하겠다
        I3 objI3 = new D();
        
        obj.A(); // class D를 가져오기에 모두 사용 가능 
        obj.A();
        
        objI2.A(); // I2는 A메소드만, B호출시 에러
        objI3.B();
    }
}

 

쉬운 예시

개발자를 고용하는데 있어서 특정 기능 ( 코딩을 하는 스타일 ) 이 궁금하지, 모든 기능 ( 코딩 스타일 + 가족관계 ) 모두가 필요한건 아니다.

 

위의 설명 바탕의 코드

interface father{}
interface mother{}
interface beliver{}
interface programmer{
    public void coding();
}

class Steve implements father, programmer, believer {
    public boid coding() {
        System.out.println("fast");
    }
}

class Rachel implements mother, programmer {
    public boid coding() {
        System.out.println("elegance");
    }
}

public class workspace {
    public static void main(String[] args) {
         progrmmer employee1 = new Steve();
         progrmmer employee2 = new Rachel();
         
         employee1.coding();
         employee2.coding();
     }
}

 

구체적으로, 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 한다.

 

Tv t = new Tv();
CaptionTv c = new CaptionTv();

지금까지는 생성된 인스턴스를 다루기 위해서는 인스턴스의 타입과 일치하는 타입의 참조변수만을 사용했다.

즉, Tv 인스턴스를 다루기 위해서는 Tv타입의 참조변수를 사용하고, CaptionTv 인스턴스를 다루기 위해서는 CaptionTv타입의 참조변수를 사용했다.

 

Tv t = new CaptionTv();

하지만, 상속의 경우에는 조상 클래스 타입의 참조변수로 자손 클래스의 인스턴스를 참조가 가능하다.

 

 

주의!

CaptionTv c = new CaptionTv();
Tv t = new CaptionTv();

실제 인스턴스가 CaptionTv타입이라 할지라도, 참조변수 t로는 CaptionTv인스턴스의 모든 멤버를 사용할 수 없다. 

( CaptionTv 인스턴스 중에서 Tv 클래스의 멤버들 ( 상속받은 멤버포함 ) 만 사용이 가능하다. CaptionTv의 것은 사용 불가능 )

-> Tv : power(), power, channel, channelUp(), channelDown()

-> CaptionTv : power(), power, channel, channelUp(), channelDown(), text, cpation()

여기서는 text랑 caption() 사용이 불가능

 

둘 다 같은 타입의 인스터스지만 참조변수의 타입에 따라 사용할 수 있는 멤버 개수가 다르다.

 

조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있다.
반대로 조상타입의 참조변수로 조상타입의 인스턴스를 참조할 수 없다.