Do it! 자바 프로그래밍 입문 8장
class 클래스식별자 extends 부모클래스_식별자 {
클래스 구현
}
부모는 자식보다 일반적이다. (자식은 부모보다 구체적이다)
상속으로 형성된 부모-자식은IS-A관계를 갖는다.
이는HAS-A관계를 갖는합성과는 다르다.
// Test.java
package classclass;
public class Test {
public static void main(String[] args) {
Child a = new Child(123, "Lee", 53);
System.out.println(a.getId()); // 123
a.setName("Kim");
System.out.println(a.getName()); // Kim
a.printInfo(); // ID : 123, Name : Kim, Age : 53
}
}
// Parent.java
package classclass;
public class Parent {
// field
protected int id;
protected String name;
// constructor
public Parent(int id, String name) {
this.id = id;
this.name = name;
}
// getter, setter
public int getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// Child.java
package classclass;
public class Child extends Parent {
// field
protected int age;
// constructor
public Child(int id, String name, int age) {
super(id, name);
this.age = age;
}
// method
public void printInfo() {
System.out.println("ID : "+id+", Name : "+name+", Age : "+age);
}
// getter setter
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
자식 인스턴스를 어딘가에서 생성하면 아래와 같은 과정을 거친다.
1. 먼저 자식 클래스의 생성자 호출되어 진입
2. 부모 생성자 super(...)가 호출
3. 부모 인스턴스 생성
4. 자식 생성자에서 나머지 내용 실행
5. 자식 인스턴스 생성
즉, 자식을 인스턴스화 하면 부모도 인스턴스화 된다.
자식에서 접근할 수 없는 private필드라도 접근만 할 수 없을 뿐, 메모리상에는 모두 적재된다.
자식을 부모 타입으로 묵시적으로 캐스팅하는 것
이것이 가능한 이유는 자식 인스턴스를 생성하면서 부모 또한 생성되었기 때문
package classclass;
public class Test {
public static void main(String[] args) {
Child a = new Child(123, "Lee", 53);
Parent b = a; // up-casting
System.out.println(b.getName()); // Lee
b.setName("new name");
System.out.println(b.getName()); // new name
/*
b.printInfo(); // compile error
// 에러나는 이유 : Parent에는 printInfo()가 없다.
*/
Child c = (Child)b; // down-casing
c.printInfo(); // ID : 123, Name : new name, Age : 53
}
}
부모를 자식으로 캐스팅하려면 명시적으로 캐스팅해야 함
위 코드의 Child c = (Child)b; 문장이 예시
instanceof키워드로 인스턴스 타입 확인가능
어떤 인스턴스가 특정 클래스로 다운캐스팅이 가능한지 여부를 확인할 때 유용
package classclass;
public class Test {
public static void main(String[] args) {
Child c1 = new Child(1, "WONJIN", 12);
Parent c2 = new Child(333, "KIM", 66666);
Parent c3 = new Parent(100, "IamParent");
// instanceof
System.out.println("<intsance> instanceof Child");
System.out.println(c1 instanceof Child); // true
System.out.println(c2 instanceof Child); // true
System.out.println(c3 instanceof Child); // false
System.out.println();
}
}
타입에 관계없이 실제 생성된 인스턴스의 메소드가 호출되는 원리
아래 코드는 Parent의 printMe()를 Child가 상속받아 오버라이드하는 모습을 보임
c2 참조변수는 Parent타입이지만, 그 인스턴스는 Child임.
가상메소드 원리에 따라 Child에서 재정의된 printMe()를 호출하는 것을 확인할 수 있음
// Test.java ( 프로그램 진입점 )
package classclass;
public class Test {
public static void main(String[] args) {
Child c1 = new Child(1, "WONJIN", 12);
Parent c2 = new Child(333, "KIM", 66666);
// [Child] id : 1 / name : WONJIN / age : 12
c1.printMe();
// [Child] id : 333 / name : KIM / age : 66666
c2.printMe();
}
}
// Parent.java
package classclass;
public class Parent {
protected int id;
protected String name;
public Parent(int id, String name) {
this.id = id;
this.name = name;
}
public void printMe() {
System.out.println("[Parent] id : " + id + " / name : " + name);
}
}
// Child.java
package classclass;
public class Child extends Parent {
protected int age;
public Child(int id, String name, int age) {
super(id, name);
this.age = age;
}
@Override
public void printMe() {
System.out.println("[Child] id : " + id + " / name : " + name + " / age : " + age);
}
}
@Override는 오버라이드 할 것임을 컴파일러에게 명시적으로 전달하기 위한 주석
@Override가 없어도 정상적으로 오버라이드 및 컴파일 됨The method <메소드 이름> of type <@Override 어노테이션이 있는 클래스> must override or implement a supertype method