다형성 : 조상 클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있도록 하는것.
실제 인스턴스가 자손클래스이고, 참조변수가 조상 클래스라면, 참조변수로는 해당 인스턴스의 모든 멤버를 사용할 수 없다.
결국 같은 인스턴스를 참조하더라도, 참조변수의 타입에 따라 사용할 수 있는 멤버의 갯수가 달라질 수 있다. <- 이게 가장 중요!
자손타입을 참조변수로 하여 조상타입의 인스턴스를 참조하는 것은 가능할까?
불가능하다.
실제 인스턴스인 조상 클래스가 사용할 수 있는 멤버보다 참조변수가 사용할 수 있는 멤버가 많기 때문이다.
이유 : 자손타입의 참조변수로 조상타입의 인스턴스를 참조하는 것은 존재하지 않는 멤버를 사용하고자 할 가능성이 있으므로 허용하지 않는 것이다.
형변환
우선 생략은 업캐스팅만 가능하다. (자손 -> 조상)
: 참조변수가 사용할 수 있는 멤버의 갯수보다 인스턴스가 갖고 있는 멤버의 갯수가 적은 것이 분명하기에 생략 가능
그럼 다운캐스팅은 왜 생략 불가능?
: 참조변수가 사용할 수 있는 멤버의 갯수를 늘리는 작업이므로,
실제 인스턴스의 멤버 개수보다 참조 변수가 사용할 수 있는 멤버의 갯수가 많아지는 것이므로 문제 발생 가능.!
형변환 : 참조변수의 타입을 변경하는 것이지, 인스턴스를 변환하는 것이 아니기 때문에 참조변수의 형변환은 인스턴스에 아무 영향도 미치지 않는다.
즉, 다운 캐스팅은 조상클래스의 멤버만 사용가능하다.
다형성이란 :
즉, 다형성은 보다 유연하고, 모듈식이며 확장 가능한 코드를 작성할 수 있도록 도와준다.
업캐스팅 : 참조변수를 통해 자손클래스의 인스턴스를 사용할 수 있지만, 자손클래스의 참조변수와 달리 참조변수가 조상클래스 타입이므로, 자손클래스만의 멤버(ex. water())는 사용할 수 없다.
업캐스팅을 사용하면 서로 다른 하위 클래스의 개체를 공통 조상 클래스의 인스턴스로 처리할 수 있다.
다운캐스팅 : 참조변수가 사용할 수 있는 멤버를 복구한다.
하위 클래스의 멤버에 다시 접근할 수 있도록 해준다!
다운캐스팅을 하기전에 instanceOf로 해당 인스턴스가 하위 클래스인지 확인하고 사용하자!
즉, 하위클래스별 멤버에 다시 접근하는데 사용된다.
주의)
SuperCar superCar = (SuperCar) car;
이런 코드는 컴파일 오류가 발생하지 않지만, 실행 시 ClassCastException이 발생한다.
이유 : 문제는 참조변수 car가 참조하고 있는 인스턴스가 Car라는데이 있다.
위에서 말했듯이 형변환은 참조변수의 타입을 변환하는 것이지, 인스턴스를 변환하는 것이 아니기 때문에 형변환은 인스턴스에 아무런 영향도 미치지 않는다.
즉, 형변환을 통해 참조변수는 SuperCar타입인데, 인스턴스는 Car이므로, 참조변수가 사용할 수 있는 멤버의 갯수가 인스턴스가 사용할 수 있는 멤버의 갯수보다 많아지는 문제가 발생하여 형변환을 할 수 없는 예외가 발생한다.
다형성의 이유 : 매개변수에 만약 어떤 특정 타입만 들어갈 수 있다고 가정해보자.
이때, 다양한 타입들로 메소드를 사용하고 싶다고 한다면, 해당 메소드의 갯수만큼 만들어야 한다.
이럴때 다형성을 사용하여 메소드 1개로 모든 매개변수를 처리할 수 있도록 만들 수 있다.
인터페이스로도 사용가능하다! (ex> interface : shape, -> 구현체 : circle, Shape circle = context.getBean(Circle.class) ,
circle.calculateArea(); -> 이런거 가능함
물론 해당 멤버변수에는 접근할 수 없다.<인터페이스를 구현한 클래스로는>)
그럼 왜 조상타입의 참조변수를 사용해서 인스턴스의 일부 멤버만을 사용하도록 해야할까?