다형성이야말로 객체지향 입문자들의 통곡의 벽이 아닐까 생각한다. 클래스와 객체는 어떻게 돌파하더라도 다형성에서 일단정지! 하고 책이든 구글이든 찾아보게 되는 것 같다.
이라는데 뭔 소린지 잘 와닿지 않는다...
Human 클래스가 있고 그것의 자식 클래스인 Man과 Woman 클래스가 있다고 가정하면, Man과 Woman은 둘 다 Human이기 때문에 Human에 Man과 Woman을 넣어서 사용할 수 있는 것이다.
다른 예로는, 컬렉션 프레임워크에 List라는 인터페이스가 있다. 구현 클래스로 ArrayList, LinkedList 등이 있는데, 객체를 생성할 때
List li = new ArrayList();
처럼 하는 경우를 많이 볼 수 있다(제네릭 생략). 이렇게 구현하면 List인터페이스에 있는 메소드까지 사용할 수 있고, 만약 나중에 ArrayList를 LinkedList로 바꾸더라도 같은 List인터페이스를 상속받았기 때문에 좀 더 쉽게 전환할 수 있다.
그러니까 결국 유연성과 코드 재사용성을 높이기 위한 일환 중 하나라는 것이다.
부모-자식 타입 간에 서로 형변환이 가능한데, 자식 타입을 부모 타입으로 올라가는(up-casting) 경우에는 생략이 가능하지만, 부모에서 자식으로 내려오는(down-casting) 것은 생략이 불가능하다. 단순히 선언만 하면 부모의 것만 사용할 수 있기 때문에 캐스팅을 해서 자식의 것까지 쓸 수 있게 해주는 것이다.
변수가 부모와 자식에 중복으로 정의되어 있으면 참조변수의 타입을 따라가고, 메소드가 그렇다면 실제 인스턴스의 타입을 따라간다.
매개변수에도 다형성을 적용할 수 있는데, 부모 클래스의 참조변수를 매개변수로 받으면 자식 클래스 참조변수까지 모두 매개가 가능하다.
instanceof는 형변환이 가능한지 여부 즉, 부모-자식관계가 맞는지 확인하는 메소드이다.
(부모) instanceof (자식)
만 False이고 이외에는 전부 True를 반환한다. 만약 부모가 Object라면 무조건 True를 반환한다.
인터페이스는 일종의 추상클래스로, 추상화가 더 잘 되어있어 추상 메소드와 상수를 가진다. 흔히 쓰이는 용도로는 쓰레드를 만들 때 Runnable 인터페이스를 상속받는 것이 있겠다.
추상클래스가 뭐냐 하면 추상메소드를 가진 클래스이다. 그럼 추상메소드는 또 뭐냐 하면, abstract 키워드를 붙여서 선언부만 만들어 놓고 구현부는 사용하는 쪽에서 구현할 수 있도록 비워둔 메소드이다.
그렇다는 것은 인터페이스에서는 대략적인 틀만 잡아두고, 세부내용은 그것을 상속받는 클래스들에서 추상메소드의 구현부를 알아서 채워서 쓰라는 뜻이다. 이렇게 해두면 일련의 규격화 또는 표준화(standardization)가 가능해져서 코드 구성에 일관성을 추구할 수 있고, 협업을 할 때도 틀만 잡아두어도 세부적으로는 각자 다른 구현이 가능해지기 때문에 구현 속도도 빨라질 수 있다.
모든 멤버 변수는 public static final이어야 하며 생략이 가능하다. 인터페이스는 인터페이스로만 상속관계를 만들 수 있고, 클래스와는 다르게 다중 상속도 가능하다.
메소드가 인터페이스 타입을 매개변수로 갖는다는 것은 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 제공한다는 것이다. 리턴타입도 같은 방식으로 기능한다. 인터페이스에서는 인스턴스를 생성할 수 없기 때문이다.
익명 클래스란 말 그대로 이름이 없고, 선언과 동시에 객체를 생성하여 일회성으로 사용되는 클래스를 말한다. 그래서 클래스의 장점인 재사용성이 오히려 도움이 안 될 때 사용하는 경우가 있다.
익명객체선언은 메소드의 매개변수에다가 바로 new 연산자를 통해 객체를 생성한 후 그 안에 클래스 내용을 기술하는 것을 말한다.
ex.exMethod1(new exClass() {
...
}
);
이런 식으로 매개변수 자리에다가 한꺼번에 기술하는 것이다. 그럼 저 객체는 저기서 역할을 다하고 사라지게 된다.