Chapter 9. 다형성 (Polymorphism)
다형성의 사전적 정의는 같은 종의 생물이지만 모습이나 특징이 고유한 특징이 다양한 성질을 의미한다.
단어의 뜻부터 어려운 이 다형성이 객체지향개념의 중요한 특징 중 하나이다.
다형성
여러 가지 형태를 가질 수 있는 능력을 의미하며,
자바에서는 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 함을 구현하는데 사용한다.
좀 더 구체적으로는 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하였다는 것이다.
코드를 통해 이해하는게 더 빠를 것 같다.
class A { public String x() { return "x"; } } class B extends A // class A를 상속받고 있는 class B { public String y() { return "y"; } } public class Main { public static void(String[] args){ A obj = new B(); obj.x(); obj.y(); // 이 녀석으로 인해 컴파일 에러 } }
class B를 obj로 인스턴스화하는데 데이터 타입이 A
실질적으로 class B를 담고 있지만 A인 것.
class A에는 메소드 y가 정의되어 있지 않다.
그래서 obj.y(); // 이 녀석으로 인해 컴파일 에러
어떤 클래스를 인스턴스화 시킬 때, 변수를 담는 데이터 타입은 그 클래스가 될 수도 있고
그 클래스의 부모 클래스가 될 수도 있다.
도대체 왜 이렇게 객체를 생성하는가 의문이 들 것이다. 다음 코드를 보자.
class A { public String x() { return "A.x"; } } class B extends A // class A를 상속받고 있는 class B { public String x() { // 오버라이딩 return "B.x"; } public String y() { return "y"; } } public class Main { public static void(String[] args){ A obj = new B(); System.out.println(obj.x()); // 이녀석은 class B에 있는 x가 실행된다. } }
A obj = new B();
이 녀석은 class B를 인스턴스화 한 obj 이지만 class A의 행세를 한다.
그 뜻은 class A에 속해 있는 메소드만 호출할 수 있다는 것이다.
즉 class B에만 속해 있는 메소드는 호출할 수 없다.
근데! class B에서 class A에 속해있던 메소드를 오버라이딩했다면
그 오버라이딩한 결과가 호출된다.
아직도 왜 이런 코드를 작성하는지 모르는 건 마찬가지이다.
코드를 하나 더 살펴보자.
class A { public String x() { return "A.x"; } } class B extends A // class A를 상속받고 있는 class B { public String x() { // 오버라이딩 return "B.x"; } public String y() { return "y"; } } class B2 extends A { public String x(){ return "B2.x" } } public class Main { public static void(String[] args){ A obj = new B(); A obj2 = new B2(); System.out.println(obj.x()); System.out.println(obj2.x()); } }
System.out.println(obj.x()); // 이녀석은 B.x를 리턴한다.
System.out.println(obj2.x()); // 이녀석은 B2.x를 리턴한다.
obj, obj2 둘은 각각 B, B2 클래스를 통해 형성된 것이지만
부모 행세를 하고 있다. 따라서 자식 클래스에서 정의된 메소드를 호출할 수 없고
오버라이딩 한 부분에 대해서만 호출한다.
즉 각각의 자식클래스에서 오버라이딩한 부분이 실행이 된다.
서로 다른 객체가 동일한 데이터 타입으로 존재하면서
각각의 클래스에 정의되어 있는 메소드를 호출할 때 각자가 정의한 대로 호출한다.
이쯤되면 이러한 의문을 갖을 수 있다.
같은 데이터 타입을 갖을 때 장점이 있나?
맞다. 데이터 타입이 같으면 메소드를 실행시키기가 편리해진다.
public static void execute(Calculator cal){ System.out.println("실행결과"); cal.run(); } public static void main(String[] args) { Calculator c1 = new CalculatorDecoPlus();//다형성 c1.setOprands(10, 20); Calculator c2 = new CalculatorDecoMinus();//다형성 c2.setOprands(10, 20); execute(c1); execute(c2); }
위 코드처럼 호출하는 메소드를 만들어두면
하나의 데이터 타입을 대상으로 여러가지를 호출할 수 있다.
다형성과 인터페이스
Interface I{} class C implements I{} public class PolymorphismDemo2 { public static void main(String[] args) { I obj = new C (); } }
어떤 클래스가 어떤 인터페이스를 구현하고 있다면
그 클래스로부터 인스턴스화 되는 인스턴스의 데이터 타입은 구현하고 있는 인터페이스로 인스턴스화 될 수 있다.
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() ; I3 objI3 = new D() ; obj. A() ; // class D가 정의한 모든 멤버를 호출할 수 있다. obj. B() ; // class D가 정의한 모든 멤버를 호출할 수 있다. objI2. A() ; // Interface I2의 데이터 타입이므로 호출 가능. //objI2.B(); // Interface I2의 데이터 타입이므로 호출 불가능. //objI3.A(); // Interface I3의 데이터 타입이므로 호출 불가능. objI3. B() ; // Interface I3의 데이터 타입이므로 호출 가능. } }
클래스가 갖고 있는 모든 메소드를 호출해야한다면(모든 기능을 사용해야한다면)
데이터 타입을 그 클래스로 지정해줘야하지만
특정한 인터페이스에 해당하는 기능만을 사용한다고 한다면
데이터 타입으로 그 기능이 속해있는 인터페이스를 데이터 타입으로 하면 된다.
나머지 기능을 마치 존재하지 않는 것처럼 할 수 있다.
포스팅 내용은 생활코딩의 이고잉님의 강의자료를 기준으로 작성하였습니다. 문제가 될 시 삭제하겠습니다.
Chapter 9. The End
'Dev.BackEnd > JAVA' 카테고리의 다른 글
#객체지향적 설계 원칙 - 이론을 통해 알아보는 객체지향 (0) | 2016.07.03 |
---|---|
# 객체 지향에 대한 이해 / 객체 지향적 설계 (0) | 2016.07.01 |
[JAVA] 8. 인터페이스 (0) | 2016.06.28 |
[JAVA] 7. 추상클래스와 추상메서드 (0) | 2016.06.27 |
[JAVA] 6. 접근제어자와 정보은닉 (0) | 2016.06.26 |