본문 바로가기

coding/Java

[Java] 상속과 참조변수, instanceof 연산자

상속(Inheritance)에 대해서 알아보자.

[Java]메소드의 오버로딩과 오버라이딩 포스트에서도 잠깐 설명했지만, 상속이란 기존에 정의된 클래스에 메소드와 변수를 추가하여 새로운 클래스를 정의하는 것을 말한다. 파이썬의 상속이랑 똑같음.

 

 

1) 상속과 생성자

다음과 같은 상속 관계를 가진 클래들이 있다고 해보자. 어떤 생성자부터 호출될까?

class SuperCls {
	public SuperCls() {
		System.out.println("저는 상위 클래스입니다.");
	}
}

class SubCls extends SuperCls {
	public SubCls() {
		System.out.println("저는 하위 클래스입니다.");
	}
}

public class FinalTermTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
	SubCls a1 = new SubCls();
	}
}

답은 

저는 상위 클래스입니다.
저는 하위 클래스입니다.

이다.

인스턴스를 SuperCls a2 = new SubCls();로 생성해도 마찬가지이다.

 

위에서는 생성자에 클래스 변수가 없어서 그냥 void함수가 호출되었다. 하지만 클래스 변수가 있다면? 키워드 super을 통해 상위 클래스의 생성자 호출을 명시할 수 있다.

class SuperCls {
	private String name;
	
	public SuperCls(String n) {
		this.name = n;
		System.out.println("저는 " + name + "입니다.");
	}
}

class SubCls extends SuperCls {
	private int age;
	
	public SubCls(String n, int a) {
		super(n);
		this.age = a;
		System.out.println("저는 " + age + "세 입니다.");
	}
}

public class FinalTermTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
	SuperCls a1 = new SuperCls("홍길동");
	SubCls a2 = new SubCls("홍길동", 35);
	}
}

저는 홍길동입니다.
저는 홍길동입니다.
저는 35세 입니다.

 

그렇다면! Static 변수도 상속이 될까?? Static 멤버는 다른 말로 클래스 멤버이다. 즉, static 멤버는 클래스당 하나만 생성되고 동일한 클래스의 객체들만 공유할 수 있다. 클래스를 상속한다는 것은 다른 클래스에서 메소드와 변수를 사용한다는 말인데, 이게 가능할까? 결론적으로 static 변수는 상속의 대상이 아니다. 하지만 접근 수준 지사자가 허용한다면 하위 클래스에서는 이름만으로 접근이 가능하고, 외부에서는 클래스 이름으로 접근할 수 있다.

class SuperCls {
	static int count = 0;
	
	public SuperCls() {
		count++;
	}
}

class SubCls extends SuperCls {
	
	public SubCls() {}
	public void showCount() {
		System.out.println(count); //하위 클래스에서 이름으로 접근하기
	}
}

public class FinalTermTest {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
	SuperCls a1 = new SuperCls(); //1
	SuperCls a2 = new SuperCls(); //2
	SubCls b1 = new SubCls(); //3 (상속은 안되지만 참조는 가능하다)
	
	b1.showCount(); 
	System.out.println(a2.count); //외부에서 클래스 이름으로 접근하기
	}
}

출력값은 둘다 3이다.

 

 

2) 상속관계

이 그림을 다시 봐보자. 하위클래스는 상위클래스보다 사용할 수 있는 메소드와 변수가 더 다양하다. 가령 heeya 클래스는 Human 클래스에 비해 공부하기, 한숨쉬기, 소리지르기 등 다양한 기능을 가지고 있다. 상위 클래스가 더 broad한 개념 아니예요?라고 물으면 맞지만 여기서의 범위는 그런 게 아닌듯.

 

IS-A의 관계를 따져보면 '스마트폰 핸드폰이다' -> 'subCLS is superCLS' 이므로 MobliePhone이 상위 클래스이다. 따라서 

  • SmartPhone phone = new SmartPhone();
  • MobilePhone phone = new SmartPhone();  --- 역은 성립하지 않음 주의!!

둘 다 가능하다.

 

참조변수의 참조 가능성 관련 예제를 하나 보자.

class MobilePhone {
	protected String num;
	
	public MobilePhone(String n) {
		num = n;
	}
	public void answer() {
		System.out.println("Hi! From " + num);
	}
}

class SmartPhone extends MobilePhone {
	private String version;
	
	public SmartPhone(String n, String ver) {
		super(n);
		version = ver;
	}
	public void playAPP() {
		System.out.println("App is running in " + version);
	}
}

public class FinalTermTest {
	public static void main(String[] args) {
	SmartPhone ph1 = new SmartPhone("010-1234-5678", "IOS12.0");
	MobilePhone ph2 = new SmartPhone("010-9876-5432", "IOS11.2.1");
	
	ph1.answer();
	ph1.playAPP();
	
	ph2.answer();
	//ph2.playAPP(); 이건 할 수 없음. 참조할 수 있는 범위가 MobilePhone 내 기능까지!

객체 ph1은 MobilePhone과 SmartPhone의 메소드 모두 접근 가능하다. 반면 ph2는 MobilePhone의 메소드만 접근 가능한데, 인스턴스는 SmartPhone으로 크게 만들었지만 접근권한은 MobilePhone 수준이기 때문이다. 

만약 형변환을 해보려고 해도

SmartPhone ph3 = ph2; ---불가능하다! 

 

 

3) Instanceof 연산자

if (참조변수 instanceof 클래스)

 

  • 참조변수가 클래스의 인스턴스를 참조하면 true 반환
  • 참조변수가 클래스를 상속하는 클래스의 인스턴스이면 true 반환
public static void main(String[] args) {
	MobilePhone phone = new SmartPhone();
    
    if (phone instanceof MobliePhone) {...} //true
    
    if (phone instanceof SmartPhone) {...} //true
}