본문 바로가기
BackEnd FrontEnd/JAVA

다형성

by forkballpitch 2017. 10. 26.
반응형


Java에서 상속을 이용하는 것과 인터페이스를 이용하는 두 가지 방식으로 다형성 참조를 생성할 수 있다.


2. 상속에 의한 다형성


Animal creature = new Horse();


Animal 이라는 클래스 타입으로 변수를 선언하면 이 변수는 Animal 의 어떤 객체라도 참조할 수 있다.

추가로, Animal 을 상속한 어느 클래스의 어느 객체라도 참조할 수 있다.

따라서 Animal 을 상속한 Horse() 객체를 참조할 수 있다.


클래스 계층구조의  최상단까지 적용하면, Object 참조 변수는 궁극적으로 모든 클래스가 Object 클래스의 자손ㅇ이기 때문에 어떤 객체든 가리킬 수 있다.


creature 는 Animal, Horse, 또는 Animal을 상속한 어떤 클래스도 참조할 수 있기 때문에 다형적이다. 이 클래스들이 모두 다른 방식으로 구현된 move 라는 메소드를 가지면 아래 호출은 해당 참조 클래스의 move() 메소드를 호출한다.


creature.move();


그러나 호출되는 메소드가 어떤 것일지는 실행시간에 결정된다. (지연 바인딩)


위 문장이 실행될 때, creature가 현재 Animal 객체를 참조하고 있다면 Animal 클래스에 속한 move() 메소드가 호출된다.

마찬가지로 Horse 객체를 참조하고 있다면 Horse 객체의 move() 메소드가 호출된다.


이렇게 상속에 따른 다형의 객체를 참조할 수 있으며, 메소드 호출 또한 실행 당시의 참조 객체의 메소드를 선택하여 호출하는 것을 상속에 의한 다형성이라고 한다.



3. 인터페이스에 의한 다형성


인터페이스 역시 클래스와 마찬가지로 변수 타입으로 사용될 수 있다.


public interface Speaker{
    
    public void speak();
    public void announce(String str);

}


인터페이스 이름, Speaker는 이제 다음과 같이 객체 참조 변수를 선언하는데 사용할 수 있다.


Speaker current;


변수 current는 Speaker 인터페이스를 구현하는 어떤 클래스의 아무 객체라도 참조하는데 사용할 수 있다.

예를들어, Philosopher 라는 Speaker 인터페이스를 구현하는 클래스가 있다면, 다음과 같이 Philosopher 객체를 Speaker 참조 변수에 배정할 수 있다.


current = new Philosopher();


이것은 Philosopher가 Speaker이기 때문에 적법하다. 이러한 점에서, 클래스와 인터페이스 간의 관계는 자식 클래스와 그 부모 클래스 간의 관계와 동일하다.  이것은 is-a 관계이다. 이러한 관계가 다형성의 기초를 형성한다.


인터페이스 참조의 유연성은 다형 참조를 생성하는 것을 허용한다. 앞서 보았듯이, 상속을 사용하여 객체들의 집합에 속한 아무 객체라도 참조할 수 있는 다형 참조를 생성할 수 있다.

물론, 그 집합에 포함된 객체들은 상속으로 연관되어 있어야 한다. 인터페이스를 사용하여 동일한 인터페이스를 구현하는 객체들에 대해서 유사한 다형 참조를 생성할 수 있다.


예를들면, Speaker 인터페이스를 구현하는 Dog 라는 클래스를 생성하면, Dog 객체도 Speaker 참조 변수에 배정될 수 있다.


Speaker guest;
guest = new Philosopher();
guest.speak();

guest = new Dog();
guest.speak()


위의 코드에서, speak() 가 처음 호출될 때, Philosopher 클래스에 정의되어 있는 speak 메소드가 호출된다. speak 메소드가 두 번째로 호출될 때는 Dog 클래스의 speak 메소드가 호출된다. 

상속에 의한 다형 참조처럼, 어느 메소드가 호출될 것인지를 결정하는 것은 참조 변수의 타입이 아니다. 이것은 메소드 호출 순간에 참조 변수가 가리키고 있는 객체의 타입에 따른다.



인터페이스 참조 변수를 사용하고 있을 때, 그 참조 변수가 가리키고 있는 객체가 인터페이스에 없는 다른 메소드를  포함하고 있다고 할지라도, 그 인터페이스에 정의되어 있는 메소드만을 호출할 수 있다.


예를들어, Philosopher 클래스가 pontificate 라는 메소드도 정의했다고 가정하면 아래 코드는 컴파일 오류를 발생시킨다.


Speaker special = new Philosopher();
special.pontificate();


이 문제는 컴파일러는 단지 그 객체가 Speaker 라는 것만을 결정할 수 있고, 그 객체가 Speaker 인터페이스의 speak() 와 announce() 메소드만 사용할 수 있다는 것만 보장하기 때문이다.


참조변수 special 이 Dog 객체를 참조한다면 컴파일러는 그 pontificate() 메소드 호출을 할 수 없다고 오류를 발생한다.


특별한 상황에서 pontificate() 메소드 호출이 적법하며 호출이 필요할때는 적절한 참조 변수로 캐스트하여 컴파일러가 허용할 수 있게 할 수 있다.


Speaker special = new Philosopher();
((Philosopher)special).pontificate();



상속에 기초한 다형 참조 변수처럼, 인터페이스 이름을 메소드 매개변수의 타입으로 사용할 수 있다. 이러한 상황에서, 인터페이스를 구현하는 어느 클래스의 어느 객체라도 그 메소드에 전달될 수 있다.


public void sayIt(Speaker current){
    
    current.speak();
    
}



다형 참조를 메소드의 형식 매개변수로 사용하는 것은 강력한 기법이다.

이것은 메소드가 전달되는 매개변수의 타입을 제어하는 것을 허용하고, 메소드에게 다양한 타입의 인자들을 받아들일 수 있는 유연성을 제공한다.



출처: http://hyeonstorage.tistory.com/266 [개발이 하고 싶어요]

반응형

'BackEnd FrontEnd > JAVA' 카테고리의 다른 글

maven에 외부 jar 사용할때 scope  (0) 2019.07.12
jar decompile  (0) 2018.12.27
동적바인딩 정적바인딩  (0) 2017.10.26
JAVA8  (0) 2017.10.24
Reflection이란  (0) 2017.09.27