Java 다형성

별의개발자커비·2023년 2월 16일
0

Java

목록 보기
45/66
post-thumbnail

다형성의 뜻이 뭔지는 중요하지 않다.
다형성을 통해 메소드, 클래스를 바라보는 시야를 넓혀보자

메소드와 다형성 overloading

class O{
    public void a(int param){
        System.out.println("숫자출력");
        System.out.println(param);
    }
    public void a(String param){
        System.out.println("문자출력");
        System.out.println(param);
    }
}

class Main {

    public static void main(String[] args) {
        O o = new O();
        o.a(1);;
        o.a("one");
    }
}
  • 클래스 O의 메소드 a는 두개의 본체를 가지고 있다. 동시에 두개의 본체는 하나의 이름인 a를 공유하고 있다. 같은 이름이지만 서로 다른 동작 방법을 가지고 있기 때문에 오버로딩은 다형성의 한 예라고 할 수 있다.

클래스와 다형성1

class A{
    public String x(){return "A.x";}
}
class B extends A{
    public String x(){return "B.x";}
    public String y(){return "y";}
}

class Main {

    public static void main(String[] args) {
        A obj = new B(); 
			// 어떠한 클래스B를 인스턴스화 시킬 때 그 인스턴스를 담는 변수obj의 데이터타입A은 
			// 그 클래스의 부모클래스A가 될 수도 있다.
			// 마치 인스턴스obj가 부모클래스A 처럼 동작할 수 있다.
			
//			obj.y(); // @실행되지 않는다. obj는(클래스A의 멤버) 메소드 y를 갖고있지 않아서
			
        System.out.println(obj.x());
        /*클래스 B를 클래스 A의 데이터 타입으로 인스턴스화 했을 때
        클래스 A에 존재하는 맴버만이 클래스 B의 맴버가 된다.*/
    }
}

클래스와 다형성2

class A{
    public String x(){return "A.x";}
}
class B extends A{
    public String x(){return "B.x";}
    public String y(){return "y";}
}
class B2 extends A{
    public String x(){return "B2.x";}
}

class Main {

    public static void main(String[] args) {
        A obj = new B();
        A obj2 = new B2();
        System.out.println(obj.x());
        System.out.println(obj2.x());
    }
}

실행 결과

B.x
B2.x
  • 서로 다른 클래스 B와 B2가 동일한 데이터 타입 A로 인스턴스화 되었다.
  • 하지만 두 인스턴스의 메소드 x를 호출한 결과는 서로 다르다.
  • 이것이 상속과 오버라이딩 그리고 형변환을 이용한 다형성이다.

실전 예제

abstract class Calculator{
    int left, right;
    public void setOprands(int left, int right){
        this.left = left;
        this.right = right;
    }
    int _sum() {
        return this.left + this.right;
    }
    public abstract void sum();
    public abstract void avg();
    public void run(){ // 5. 근데 여기 run의 sum, avg는 avstract라 아래의 구체 로직에서 실행
        sum();
        avg();
    }
}
class CalculatorDecoPlus extends Calculator { // 4. 근데 run이 없으니 부모클래스에 있는 run 실행
    public void sum(){
        System.out.println("+ sum :"+_sum()); 	// 6. 얘네가 실행되고
    }
    public void avg(){
        System.out.println("+ avg :"+(this.left+this.right)/2); // 7. c2는 이게 실행됨
    }
}
class CalculatorDecoMinus extends Calculator {
    public void sum(){
        System.out.println("- sum :"+_sum());
    }
    public void avg(){
        System.out.println("- avg :"+(this.left+this.right)/2);
    }
}

class Main {
    public static void execute(Calculator cal){ 
			// 3. cal 자리는 Cal 부모클래스 안이여야 = c1(=CalculatorDecoPlus) 
			// = CalculatorDecoPlus.run이 됨
        System.out.println("실행결과");
        cal.run();
    }

    public static void main(String[] args) {
        Calculator c1 = new CalculatorDecoPlus(); // 1. 인스턴스c1이란 = CalculatorDecoPlus클래스를 말함
        c1.setOprands(10, 20);

        Calculator c2 = new CalculatorDecoMinus();
        c2.setOprands(10, 20);

        execute(c1); // 2. 이 c1을 excute 함수함
        execute(c2);
    }
}
  • 근데 최종적으로 중복되는 코드가 최소화 되는 버전이 이것
  • 이 맥락에서의 다형성이란 하나의 클래스(Calculator)가 다양한 동작 방법(ClaculatorDecoPlus, ClaculatorDecoMinus)을 가지고 있는데 이것을 다형성이라고 할 수 있겠다.

인터페이스와 다형성

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 PolymorphismDemo3 {
    public static void main(String[] args) {
        D obj = new D();
        I2 objI2 = new D(); 
        // objI2라고 하는 클래스D의 인스턴스가 자기가 마치 인터페이스I2인 것 처럼 행세 
        // = 데이터타입이  I2 = 메소드A만을 갖고있는 것처럼 작동
        I3 objI3 = new D();
         
        obj.A();
        obj.B();
         
        objI2.A(); 
//		objI2.B(); // B는 I3에서 정의하므로 인터페이스I2입장에서는 없으니 오류
         
//      objI3.A(); // 같은 이유로 오류
        objI3.B();
    }
}
  • 이것은 인터페이스의 매우 중요한 특징 중의 하나를 보여준다.
  • 인스턴스 objI2의 데이터 타입을 I2로 한다는 것은 인스턴스를 외부에서 제어할 수 있는 조작 장치를 인스턴스 I2의 맴버로 제한한다는 의미가 된다.
  • 인스턴스 I2와 I3로 인해서 하나의 클래스가 다양한 형태를 띄게 되는 것이다.

비유

interface father{}
interface mother{}
interface programmer{
    public void coding();
}
interface believer{}
class Steve implements father, programmer, believer{
    public void coding(){
        System.out.println("fast");
    }
}
class Rachel implements mother, programmer{
    public void coding(){
        System.out.println("elegance");
    }
}
public class Workspace{
    public static void main(String[] args){
        programmer employee1 = new Steve();
        programmer employee2 = new Rachel();
         
        employee1.coding();
        employee2.coding();
    }
}
  • 위의 코드를 보면 알겠지만 Steve와 Rachel의 사용자인 직장에서는 Steve와 Rachel의 인터페이스인 programmer를 통해서 두사람과 관계하게 된다. 두 사람이 어떤 종교나 가족관계를 가졌건 인터페이스 programmer을 가지고 있다면 고용할 수 있다. 회사에서는 코딩을 할 수 있는 사람이 필요하고 어떤 사람이 programmer라는 인터페이스를 구현하고 있다면 그 사람은 반드시 coding이라는 메소드를 구현하고 있을 것이기 때문이다. 또 두 사람에게 업무를 요청 할 때는 programmer라는 인터페이스의 메소드인 coding을 통해서 요청하면 된다. 하지만 두 사람의 성향이나 능력에 따라서 그 업무를 수행한 결과는 다른데 Steve는 빠르게 코딩하고 Rachel은 우아하게 코딩하고 있다.

( 출처 생활코딩 https://www.opentutorials.org/course/1194/6127 )

0개의 댓글