자식 클래스는 부모 클래스를 상속받을 수 있다.
상속을 받으면 무슨 일이 발생할까?
field
, method
를 자식 클래스에서 정의하지 않고 사용할 수 있다.상속은 객체지향 프로그래밍에서 아주 중요한 개념이다.
포유류와 인간 클래스가 있다고 생각해보자
포유류 > 사람 으로 인간은 포유류에 속할 수 있다.
이를 클래스로 나타내면 아래와 같은 코드를 작성함으로써 상속을 구현할 수 있다.
public Human extend Mammalia {
...
...
}
또한 큰 범주의 클래스에 작은 범주의 클래스를 저장할 때는 캐스팅이 필요없다.
포유류 인간 = new 사람()
캐스팅 필요없음사람 인간 = new 포유류()
안됨사람 인간 = (사람) new 포유류()
캐스팅하면 됨 Mammalia person1 = new Human();
person1.getHeight();
// person1.getNationality(); 자식 클래스의 메소드, 속성에는 캐스팅 없이 접근 불가
// 그렇다면 왜 이렇게 쓸까? 다형성 때문에?
Human person2 = new Human();
person2.getNationality(); // 자식, 부모 모두 접근 가능
final
명령어와 함께 클래스를 정의하면 부모 클래스가 될 수 없다. 만약 다른 클래스에 extends A
를 추가하면 컴파일 에러가 발생한다.
대표적으로
java.lang.String
이final class
의 예시이다.
final A {
...
}
java in a nutshell에서는 우리가 정의하는 대부분의 클래스들이
final
이여야한다고 말한다.
클래스를 정의할 때 자식 클래스가 생기고 자식 클래스가 로직을 수정하는 것을 원치 않는다면final
클래스를 붙이라고 한다.
Object
클래스이다.Object
를 루트로 가지는 트리 구조이다.superclass
/ 자식 클래스는 subclass
라고 부른다.super
는 부모클래스를 나타낸다. this
와 비슷한 동작을 한다.
마찬가지로 super
와 super()
가 있다.
super()
는 자식 클래스의 생성자에서 선언할 수 있으며 선언 시 부모 클래스의 생성자를 호출한다.
field
나 method
들을 조작하는 로직들보다 먼저 선언해야된다는 말이다.모든 클래스를 생성할 때 제일 먼저 object의 생성자가 실행된다.
Object는 하나의 생성자만 가지고 있다.
생성자가 연쇄적으로 호출된다는 뜻이다. 객체가 생성될 때면 항상 생성자 체인이 호출된다 클래스 계층의 루트인 Obejct 까지 거슬러 올라가서.
왜냐하면 수퍼클래스의 생성자는 항상 서브클래스 생성자 로직에 첫줄에 선언하기 때문이다.
생성자 체이닝을 설명하기 전에 앞서 설명한 것들을 다시 나열해보자
Object
는 루트 클래스이다.super()
는 자식 생성자의 어떤 로직보다도 먼저 선언되어야 한다.위와 같은 이유로 모든 클래스는 인스턴스화될 때 부모 클래스의 생성자가 super()
에 의해 호출된다.
super()
는 계속해서 부모 클래스에 접근해 결국에는 Object
클래스의 생성자부터 실행한다.
이런 동작을 constructor chaining
이라고 한다.
abstract
를 붙임으로써 추상 클래스를 생성할 수 있다.
abstract method
가 있으면 반드시 abstract
로 선언되어야 한다.abstract class
는 인스턴스화 할 수 없다.abstract class
를 상속받은 클래스는 abstract method
들을 오버라이딩해야한다. 그리고 다른 부모-자식 관계처럼 abstract
가 아닌 method
나 field
를 제공받는다.abstract class
를 상속받은 클래스를 concrete subclass
라고 부르기도 한다.abstract method
를 implement
하지 않으면 그 subclass
자체도 추상 클래스가 되어버린다.private
, static
, final
method
들은 abstract
와 함께 쓸 수 없다. 왜냐하면 private
, static
, final
은 오버라이딩할 수 없기 때문이다. 같은 이유로 final class
는 어떠한 abstract method
도 포함할 수 없다.abstract method
를 하나도 선언하지 않고서 class
를 abstract
로 선언할 수 있다. 이를 통해 반드시 하나 이상의 자식 클래스를 가지겠다고 명시할 수 있다. 물론 인스턴스화는 불가능하다.
Classloader
클래스가abstract method
를 포함하지 않는abstract class
의 좋은 예시이다.
5주차 클래스 포스팅에서 오버라이딩을 정리했다.
Object
는 자바 클래스 구조의 루트 노드이다.Object
는 유일하게 수퍼 클래스가 없다.Object
를 직/간접적으로 수퍼 클래스로 가지지만 extend
가 필요없다.Object
의 생성자는 하나 뿐이며 다른 클래스를 인스턴스화 할 때 항상 Object
의 생성자가 먼저 호출된다.어떤 메소드를 호출할지 결정하여 호출하는 과정을 말한다.
Static Method Dispatch, Dynamic Method Dispatch, Double Dispatch 가 있다.
위에서 언급한 코드를 먼저 보자
Human person2 = new Human();
person2.getNationality(); // 자식, 부모 모두 접근 가능
위의 코드처럼 호출해야 하는 함수가 명확할 때 즉, 컴파일 시점에 확정될 때를 말한다.
abstract class Mammalia {
abstract String getName();
}
public class Human {
@Override
public String getName() {
return "사람입니다.";
}
}
public class Whale {
@Override
public String getName() {
return "고래입니다.";
}
}
public static void main(String[] args) {
Mammalia person = new Human(); << 둘 다 컴파일단에서는 Mammalia의 getName인지
person.getName();
Mammalia whale = new Whale(); << Whale의 getName인지 알 수 없다.
whale.getName();
}
위와 같이 abstract
혹은 interface
의 메소드를 오버라이딩한 함수를 호출할 때 메소드가 동적으로 결정되는 것이다.
런타임 전에는 객체가 생성되지 않기 때문에 컴파일러는 Mammalia
의 자식인 Human
과 Whale
이 생성되는지 알 수 없다.
프로그램을 실행 시에는 동적으로 확인이 가능하다.
자바는 메소드를 호출할 때 호출한 객체를 매개 변수에 묵시적으로 함께 전달한다고 한다. 그렇기 때문에 메소드 내부에서 this
를 통해 호출 객체에 대한 참조가 가능하다고 한다.