오버라이딩에 의한 다형성
package s07.p01;
class Foo {
public void methodA() {
}
}
class Bar extends Foo{
public void methodB(){}
}
public class Poly01 {
public static void main(String[] args) {
Bar bar = new Bar(); // 자식 객체를 생성한 것
Foo foo = (Foo)bar; // 부모 클래스 타입으로 자식 객체를 래퍼런스함
// 여전히 힙 영역에는 자식 객체가 있습니다.
foo.methodA();
//foo.methodB();// 이 경우 자식 클래스 메소드는 사용이 불가능
//문법적으로 사용이 불가. Foo 타입이기 때문에 자식객체이지만 문법적으로 제한이됨
Foo foo1 = new Foo();
// Bar bar1 = (Bar)foo1; // 자식 클래스 타입으로 부모 객체를 받음
// 문법오류X지만 실행시 오류가 발생(런타임 오류)
// bar1.methodA(); // 문법오류 x 애초에 성립이 안됨
// bar1.methodB(); // 문법오류 x
// 문법적으로는 변수에 자식객체가 들어있는지 부모객체가 들어있는지는 알수가없음 => 그래서 문법ok
// 위 아래 bar1은 문법적으로 똑같이 인식함
// 자식 클래스 자료형으로 객체를 보려 하지만, 부모 객체 부분만 있기 때문에
// 런타임에서 오류를 발생시킴 = > 실행은 됬지만 오류가 발생하는 상황(실행하기 위한 문법은 성립)
// 클래스가 Bar > Foo 인 상황에서 Bar에 Foo를 대입을 하려고 하니까 빈부분이 생기고 에러가생김 => 정보부족
Bar bar1 = (Bar)foo; // 자식 클래스 타입으로 자식 개체를 받음(원래있던자리로도랑옴)
// 힙 영역에는 계속 자식 객체가 있었던 것.
bar1.methodA();
bar1.methodB();
Foo foo2 = new Bar(); // 업캐스팅
Bar bar2 = (Bar)foo2; // 다운캐스팅 => (Bar)안붙이면 에러발생
}
}
부모 클래스 타입으로 자식클래스의 객체를 생성한 경우
부모 객체와 자식 객체 모두 생성되지만 문법상 부모객체로만 접근이 가능하다
부모 클래스의 메서드와 부모 클래스의 메서드를 오버라이딩한 메서드는 사용가능하다
자식 클래스의 메서드는 사용 불가능
부모 클래스의 변수에는 접근 가능
자식 클래스의 변수에는 접근 불가
부모 클래스 타입으로 자식클래스의 객체를 생성한 경우 다시 자식 클래스 타입으로 형변환 할 수 있다
상위 자료형에서 하위 자료형으로 옮기는 다운캐스팅 상황이어서 (자료형)을 붙여줘야한다.
위와 같이 형변환 하면 부모클래스의 메서드와 자식클래스 메서드 모드 접근가능하다
문법오류는 없어서 에러는 안뜬다 하지만 실행시 에러가 발생 하게 된다.
해당 객체를 자식 클래스의 유형으로 보려 하지만 부모 객체 부분만 있기 때문에 이러한 오류 발생하게 된다
멤버 변수의 재정의는 선언된 객체의 타입을 따른다. (문법적으로 본다)
메소드 오버라이딩은 메모리상의 객체 타입을 따른다. (실제 객체로 본다)
- 자녀 객체에서 오버라이딩된 메소드라면 오버라이딩된 객체에 접근하게 된다
- 이를 가상 메소드 호출; Virtual method call 호출이라고 한다
class Foo {
static public String y = "Super Class";
public String x = "Super";
public void methodA(){
System.out.println("Super Method");
}
}
class Bar extends Foo {
static String y = "Sub Class";
public String x = "Sub";
@Override
public void methodA() {
System.out.println("Sub Method");
}
}
// 변수 x와 methodA둘다 오버라이드함
public class Ply02 {
public static void main(String[] args) {
Bar bar = new Bar();
Foo foo = (Foo)bar;
System.out.println(bar.x); //Sub
bar.methodA(); // Sub Method
System.out.println(foo.x); //Super
// 멤버 변수의 재정의는 선언된 객체의 타입을 따른다(문법적으로 본다)
foo.methodA(); //Sub Method
// 메소드 오버라이딩은 메모리상의 객체 타입을 따른다.(실제 객채로 본다)
// Foo에 있는 메소드는?
// Virtual method call: 가상메소드 호출; 실제로 사용되지 않지만 호출되지는않음
// 문법을 위해 호출이 되어야 되지(재정의된거니까)그러나 쓰이지는 않음
System.out.println(Foo.y); // Super Class
System.out.println(Bar.y); //Sub Class
System.out.println(bar.y); // Sub Class
System.out.println(foo.y); // Super Class
// 스태틱 변수도 문법적으로 따라간다...
}
}
부모 클래스 타입으로 자식클래스의 객체를 생성한 경우
자식 클래스에 의해 메소드가 오버라이딩된 경우에, 부모 클래스의 메소드를 호출하는 행위가 '가상 메소드 호출' 이다
어떤 메소드를 호출할지 결정하는 행위가 아니라, 자식 클래스의 메소드를 호출해야 하는 경우인데 부모 클래스의 메소드를 통해서 호출하는 것을 의미하는 것입니다.
public void method(){ //부모클래스의 메서드
son.method() // 자식클래스의 오버라이드된 메서드
}
즉, 오버라이딩되지 않은 경우에는 가상 메소드 호출이 발생하지 않는다.
package s07.p03;
class Foo {
public Foo getInstance(){
return this;
}
}
class Bar extends Foo{
@Override
public Bar getInstance() {
return this;
}
// public Foo getInstance(){ (Foo)getInstance()} 와 비슷하다...라는건가
// 원래는 오버라이드할때 return타입도 같아야함, 그러나 이런경우는 예외적으로 인정을해줌
// Foo에서 Foo를 return하나 Bar에서 Bar를 return 같은거라고 인식을 해준 거지지 // 오버로딩 아니고 오버 라이딩, 입력파라미터 같음
// 공변반환타입 - 같이 변한다 CoVariant'
// 리턴 타입은 클래스 밖에 들어갈게 없음 //
}
public class Poly03 {
}