자바의 상속은 익숙하고 자주 쓰는 문법이지만 그 본질은 잘 이해하지 못하고 있다고 느껴 다시 한번 정리해 보려고 합니다.
💡 상속은 재활용을 위한 문법이 아니고, A, B, C 클래스의 공통적인 규약을 적용시켜주는 것입니다.
class Man {
String name;
public void tellYourName() {
System.out.println("My name is " + name);
}
}
class BusinessMan extends Man {
String company;
String position;
public void tellYourInfo() {
System.out.println("My company is " + company);
System.out.println("My position is " + position);
tellYourName();
}
}
위와같이 특정 클래스이름 뒤에 extends [상속받을 클래스] 를 추가해 상속을 받을 수 있습니다.
위의 예시에서는 BusinessMan이 Man 클래스를 상속받고 있습니다. 클래스를 상속받으면 해당 클래스의 필드 변수와 메소드를 가져와서 사용할 수 있습니다. (BusinessMan이 Man의 tellYourName() 호출)
⛔️ 상속된 메소드와 필드변수가 Private으로 선언되었을 경우 접근이 불가능하고,
Public으로 선언 되었을 경우만 가능합니다.
상속의 대상이 되는 클래스 : 상위 클래스, 부모 클래스
상속을 하는 클래스 : 하위 클래스, 자식 클래스
상속의 관계는 위,아래 또는 부모와 자식으로 표현합니다.
class AAA {
public AAA () {
System.out.println("I'm AAA");
}
}
class BBB {
public BBB () {
System.out.println("I'm BBB");
}
}
CCC는 AAA,BBB 두 개의 클래스 모두를 상속 받을 수 없고 오직 하나의 클래스만 상속 가능합니다.
❌ 다중 상속 불가능
class CCC extends AAA,BBB { public CCC () { System.out.println("I'm CCC"); } }
⭕️ 단일 상속 가능class CCC extends AAA { public CCC () { System.out.println("I'm CCC"); } }
기본적으로 클래스는 생성시에 생성자를 호출합니다.
상속을 받고 있는 경우라면 부모 클래스의 생성자도 호출해야 합니다.
class SuperCLS {
String name;
public SuperCLS () {
this.name = "superClass"
}
public SuperCLS (String name) {
this.name = name;
}
}
class SubCLS extends SuperCLS {
public SubCLS (String name) {
super(name); // 부모 클래스의 생성자 호출
System.out.println("I'm Sub Class");
}
}
super()는 부모의 생성자를 의미합니다. super(name) 과 같이 부모의 다른 생성자들도 호출 가능합니다.
super()을 명시하지 않는다면, 컴파일러가 자동으로 셍성자의 맨 윗줄에 super()를 삽입하여 실행합니다.
클래스(스태틱) 변수, 메소드는 전체가 공유하는 데이터 인데 상속이 될까? 의문이 듭니다. 아래 count 변수와 같이 클래스 내부에 선언된 클래스 변수는 과연 상속이 될까?
class SuperCLS {
protected static int count = 0; // 클래스 변수
public SuperCLS() {
count++; // 클래스 내에서는 직접 접근 가능
}
}
class SubCLS extends SuperCLS {
public void showCount() {
System.out.println(count);
}
}
정답부터 이야기 하자면 상속이 되지 않습니다.
당연한 이야기로 비유를 들자면 부모의 건물에 다른 사람이 월세로 살고 있다고 가정했을 때, 부모가 자식에게 건물을 물려줄 수는 있습니다. 그러나 건물 안 월세로 살고 있는 다른 사람의 가구까지는 물려줄 수 없습니다. 당연한 이야기이지만, 부모도 다른사람의 가구는 자신의 것이 아니기 때문에 자식에게 물려줄 수 없는 것입니다.
이와 같은 논리로 static 으로 선언된 count 는 전역변수이기 때문에 부모 클래스인 SuperCLS에 선언 되어있더라도 자식 클래스에게 물려줄 수는 없는 것입니다.
집 공간을 내어준 특권 - 직접 호출
그러나 집 공간을 내어준 부모는 하나의 특권을 가집니다.
보통은 클래스 변수를 호출할 경우
SuperCLS.count
와 같이 클래스 이름.변수이름 의 형태로 호출해야 하지만, 해당 클래스 변수를 선언한 클래스 내부에서는
class SuperCLS {
protected static int count = 0; // 클래스 변수
public SuperCLS() {
count++; // 클래스 내에서는 직접 접근 가능
}
}
count 만으로 호출이 가능합니다.
하위 클래스에서도 이름만으로 접근이 가능합니다.
단, 클래스 변수의 접근 수준 지시자가 public 이나 protect로 허용될 경우에만 가능합니다. (private는 접근 불가)
class SubCLS extends SuperCLS {
public void showCount() {
System.out.println(count);
}
}