상속과 참조변수의 관계
스마트폰과 모바일폰이 존재하고, 스마트폰은 모바일폰을 상속한다.
이러한 경우에,
모바일폰 참조변수로 스마트폰 인스턴스를 참조할 수 있고
스마트폰 참조변수로 스마트폰 인스턴스를 참조할 수 있다(이는 당연한 얘기)
모바일폰 참조변수는 스마트폰 인스턴스의 주소값을 가르키지만 "모바일폰 참조변수" 이기 때문에 모바일폰 클래스의 수준까지만 참조가 가능하다.
즉, 모바일폰 참조변수로 스마트폰 인스턴스를 참조하였을때는 모바일폰 클래스의 기능만 수행이 가능하다.
가리키는 것은 가능, but 접근 범위가 달라짐.
역으로는 불가능하다. 위의 그림을 참고해봐도 알겠지만 스마트폰의 기능범위가 더 넓기 때문에 스마트폰의 참조변수가 모바일폰의 인스턴스를 가리킬 수는 없다.
//Phone.java
public class Phone {
public static void main(String[] args) {
SmartPhone ph1 = new SmartPhone("010-111-222", "Nougat");
MobilePhone ph2 = new SmartPhone("016-555-333", "Nougat");
//MobilePhone 참조변수로 SmarPhone 인스턴스 참조가능, but 제한된 참조!
ph1.answer();
ph1.playApp();
System.out.println();
ph2.answer();
//ph2.playApp(); -> Error !
}
}
class MobilePhone {
protected String number;
public MobilePhone(String num) {
number = num;
}
public void answer() {
System.out.println("Hi~ from " + number);
}
}
class SmartPhone extends MobilePhone {
private String androidVer;
public SmartPhone(String num, String ver) {
super(num);
androidVer = ver;
}
public void playApp() {
System.out.println("App is running in " + androidVer);
}
}
위의 코드에서 cake 참조변수 ca3은 CheeseCake인스턴스를 가리키고 있다.
그리고 ca3은 cake 클래스의 기능만 수행할 수 있을것이다.
그 상태로 CheeseCake 참조변수에 할당할려고 할시 오류가 발생한다.
이는 컴파일러에서 ca3이 참조하는 수준을 보고 판단하기 때문이다.
컴파일러는 ca3가 참조하는 인스턴스의 정확한 정보를 유지하지는 않는다.
ca3은 cake를 참조하는 참조변수라고 생각하기 때문에, Cheesecake 참조변수로의 대입에 오류를 발생시킨다.
메소드 오버라이딩
public class Cake {
public void yummy() {
System.out.println("Yummy Cake");
}
public static void main(String[] args) {
Cake c1 = new CheeseCake();
CheeseCake c2 = new CheeseCake();
c1.yummy();
c2.yummy();
}
}
class CheeseCake extends Cake {
public void yummy() {
System.out.println("Yummy Cheese Cake");
}
}
실행결과
자식 클래스에서 부모 클래스의 메소드를 오버라이딩하면, 부모 클래스의 메소드는 가려진다.
위의 코드에서 Cake 참조변수로 CheeseCake를 참조했음에도 불구하고, Cake의 yummy 메소드가 실행되는게 아닌, CheeseCake의 yummy메소드가 실행된다.
오버라이딩 된 메소드는 외부에서 . 연산을 통하여 실행이 불가능하다.
단, Cake c1 = Cake(); c1.yummy();
의 접근이 불가능하다는 뜻이 아니다! 참조변수가 CheeseCake 인스턴스를 가리킬 경우에만 해당되는것을 명심.
오버라이딩 된 메소드를 호출하는 법
public class Cake {
public void yummy() {
System.out.println("Yummy Cake");
}
public static void main(String[] args) {
Cake c1 = new CheeseCake();
CheeseCake c2 = new CheeseCake();
c1.yummy();
c2.yummy();
}
}
class CheeseCake extends Cake {
public void yummy() {
super.yummy(); //가려진 메소드를 호출함!
System.out.println("Yummy Cheese Cake");
}
}
실행결과
인스턴스 변수는 오버라이딩 가능?
출처 : 윤성우의 열혈Java 프로그래밍