본문 바로가기

Language/Java

다형성 (Polymorphism)

클래스의 인스턴스를 변수로 선언할 때, 해당 클래스의 데이터 타입으로 선언하지 않고, 부모 클래스나 인터페이스를 데이터 타입으로 선언할 수도 있다.

 

이렇게 객체의 타입이 부모 클래스, 인터페이스, 자식 클래스 등 여러 형태인데도 인스턴스로 만든 객체(자식 클래스의 인스턴스)와 같이 행동하는 것을 다형성(polymorphism)이라고 한다.

 

하나의 클래스가 여러 가지의 얼굴을 가지게 하는 것이 다형성이다.

 

interface Calculable {
	double PI = 3.14;
	int sum(int v1, int v2);
}
interface Printable {
	void print();
}
class RealCal implements Calculable, Printable {

	public int sum(int v1, int v2) {
		return v1 + v2;
	}

	public void print() {
		System.out.println("this is RealCal!!!");
	}	
	
}

public class InterfaceApp {

	public static void main(String[] args) {
		RealCal c = new RealCal();
		System.out.println(c.sum(2, 1));
		c.print();
		System.out.println(c.PI);
	}

}

 

위 코드를 볼 때, RealCal은 Calculable, Printable을 구현하고 있다. 여기서 c는 RealCal의 인스턴스를 가리킨다. 그리고 데이터 타입은 RealCal이다.

 

그런데 이 데이터 타입은 클래스를 지정할 수도 있고, 이 클래스가 구현하고 있는 인터페이스를 지정할 수도 있다. 예를 들어,

 

interface Calculable {
	double PI = 3.14;
	int sum(int v1, int v2);
}
interface Printable {
	void print();
}
class RealCal implements Calculable, Printable {

	public int sum(int v1, int v2) {
		return v1 + v2;
	}

	public void print() {
		System.out.println("this is RealCal!!!");
	}	
	
}

public class InterfaceApp {

	public static void main(String[] args) {
		Calculable c = new RealCal();	// 데이터 타입을 RealCal 말고 Calculable로 지정
		System.out.println(c.sum(2, 1));
		c.print(); // Compile Error
		System.out.println(c.PI);
	}

}

 

위 코드처럼 데이터 타입을 Calculable로 지정을 하면, c는 이제 Calculable로서 동작한다. Calculable은 sum이라는 메소드와 PI라는 변수로 이루어져 있다. 그렇기 때문에, Printable에 있는 print라는 메소드는 Calculable의 소속이 아니다. 그래서 접근할 수 없게 된다. 감춰지게 되는 것이다. 만약 데이터 타입을 Printable로 한다면, 반대로 c는 Printable로서 동작한다. 그러면 print()는 접근 가능하지만, sum()과 PI는 접근할 수 없게 된다.

 

수많은 기능 중 원하는 기능만 사용할 수 있도록 기능을 감출 수 있다. 여기서는 RealCal이 이 인스턴스에서는 Calculable로서 사용된다고 지정을 하게 되면, Calculable에 해당되는 기능을 제외한 나머지 메소드와 변수는 감춰진다는 것이다. 그것을 통해서 우리가 RealCal이라는 것을 우리의 관심사에 집중해서 최소한의 학습을 통해서 사용할 수 있다는 것이다.

 

한편, 내가 Printable이라는 기능만 이용하겠다고 지정해 놓으면, 나중에 다른 클래스 예를 들어,

 

interface Calculable {
	double PI = 3.14;
	int sum(int v1, int v2);
}
interface Printable {
	void print();
}
class RealCal implements Calculable, Printable {

	public int sum(int v1, int v2) {
		return v1 + v2;
	}

	public void print() {
		System.out.println("this is RealCal!!!");
	}	
	
}

class AdvancedPrint implements Printable {
    public void print() {
    	System.out.println("This is RealCal!!");
    }
}

public class InterfaceApp {

	public static void main(String[] args) {
		Printable c = new AdvancedPrint();	// RealCal()을 AdvancedClass()로 대체
		c.print();
	}

}

 

위 코드에서처럼, 다른 클래스인 AdvancedPrint()를 RealCal()의 자리로 대체해도 우리가 예상했던 것대로 동작할 것이라는 것을 어느 정도 확신할 수 있게 된다.

 

즉, 우항에 오는 클래스의 종류를 우리가 인터페이스를 통해서 지정하면, 여기에는 똑같은 인터페이스를 구현하고 있는 클래스라면 누구든지 올 수 있다.

 

즉, 호환성을 보장할 수 있다는 것이다.

 

 

 

 

 

[참고자료]

https://docs.oracle.com/javase/tutorial/java/IandI/interfaceAsType.html

 

Using an Interface as a Type (The Java™ Tutorials > Learning the Java Language > Interfaces and Inheritanc

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Java Language Changes for a summary of updated

docs.oracle.com

https://brunch.co.kr/@mystoryg/60

 

다형성과 동적 바인딩

다형성(Polymorphism)과 동적 바인딩 객체지향에는 크게 4개의 특징이 있다. 바로 추상화, 캡슐화, 상속, 다형성이다. 객체지향 언어인 자바도 예외일 수 없다. 자바에서 상속을 배우면 캡슐화와 다

brunch.co.kr

'Language > Java' 카테고리의 다른 글

예외 처리 (Exception Handling)  (0) 2022.11.26
예외 (Exception)  (0) 2022.11.26
인터페이스 (Interface)  (0) 2022.11.20
상속과 생성자  (0) 2022.11.14
this, super  (0) 2022.11.14