What You Can Do in a Subclass
Private Members in a Superclass
if (obj instanceof MountainBike) {
MountainBike myBike = (MountainBike)obj;
}
superclass의 인스턴스 함수와 같은 signature와 return 타입인 subclass의 인스턴스 함수는 superclass 인스턴스 함수를 override 한다.
subclass의 함수를 override하는 능력은 subclass가 자신과 행동이 비슷한 superclass로부터 상속받고 필요할 경우 행동을 변경하게 해준다.
오버라이딩 함수는 대체하는 함수와 같은 함수명, 같은 파라미터의 개수와 타입, 같은 리턴타입을 가진다.
오버라이딩 함수의 리턴 타입은 오버라이딩하는 함수의 리턴 타입의 subtype일 수 있다. 이 subtype은 covariant return type이라고 부른다.
함수를 오버라이딩할 때, @Override 어노테이션을 사용함으로써 컴파일러에게 superclass의 함수를 오버라이딩을 알릴 수 있다. 어떤 이유로 컴파일러가 오버라이딩 함수가 superclass에 존재하지 않음을 발견하면 에러를 발생시킨다.
subclass가 superclass의 static 함수와 같은 함수 시그니처를 가진 static 함수를 정의하면, subclass에 존재하는 그 함수는 superclass의 함수를 숨긴다.
static 함수를 숨기는 것과 instance 함수를 override하는 것의 차이는 중요한 함축을 가진다.
Cat myCat = new Cat();
Animal myAnimal = myCat;
Animal.testClassMethod();
myAnimal.testInstanceMethod();
인터페이스에 존재하는 Default 함수와 abstract 함수는 instance 함수와 같은 방식으로 상속된다.
그러나 클래스나 인터페이스의 supertype이 같은 시그니처를 가진 다중 default 함수들을 제공하면, 자바 컴파일러는 상속 규칙을 적용해 name conflict 문제를 해결한다.
두개 이상의 독립적으로 정의된 default 함수들이 충돌하거나 default 함수와 abstract method가 충돌하면 자바 컴파일러는 컴파일 에러를 생성한다. 이 경우 반드시 명시적으로 supertype 함수를 override 해야한다.
implement한 여러 인터페이스가 같은 시그니처를 가진 default 함수를 가진 경우 super 키워드를 사용해 호출할 수 있다.
public class FlyingCar implements OperateCar, FlyCar {
// ...
public int startEngine(EncryptedKey key) {
FlyCar.super.startEngine(key);
OperateCar.super.startEngine(key);
}
}
super 전에 오는 이름은 직접 호출된 함수를 정의하거나 상속받은 superinterface를 직접적으로 참조해야한다.
이러한 형태의 함수 호출은 같은 시그니처의 default 함수들을 가진 다중 구현된 인터페이스들을 구분짓는데에만 적용되지 않는다.
super 키워드를 클래스와 인터페이스에 존재하는 default 함수를 호출할 경우에도 사용할 수 있다.
클래스로부터 상속된 instance 함수들은 인터페이스의 abstract 함수들을 override할 수 있다.
Polymorphism(다형성)의 사전적 정의는 종이나 개체가 많은 다른 형태나 상태를 가질 수 있다는 생물학의 원리이다.
이 원리는 자바같은 객체지향 프로그래밍 및 언어에도 적용할 수 있다.
어떤 클래스의 subclass들은 그들의 고유한 행동을 정의하면서 몇개의 부모클래스와 같은 기능성을 가질 수 있다.
public class TestBikes {
public static void main(String[] args){
Bicycle bike01, bike02, bike03;
bike01 = new Bicycle(20, 10, 1);
bike02 = new MountainBike(20, 10, 5, "Dual");
bike03 = new RoadBike(40, 20, 8, 23);
bike01.printDescription();
bike02.printDescription();
bike03.printDescription();
}
}
Invocation of a superclass constructor must be the first line in the subclass constructor.
superclass 생성자 호출은 언제나 subclass 생성자의 첫 줄에 와야한다.
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.
만약 생성자가 superclass 생성자를 명시적으로 호출하지 않으면, 자바 컴파일러가 superclass의 아규먼트가 없는 생성자 호출을 자동적으로 삽입한다.
만약 superclass가 아규먼트없는 생성자를 가지지 않는다면 컴파일타임 에러를 받는다. Object는 그런 생성자를 가지므로 Object만 상속받은 클래스인 경우 문제 없다.
만약 subclass 생성자가 superclass의 생성자를 명시적으로든 암시적으로든 호출한다면 Object 생성자까지 올라가면서 연속적으로 생성자 호출이 일어남을 알 수 있다.
이것을 constructor chaining이라고 한다.
만약 클래스 또는 클래스의 superclass중에 하나가 Cloneable 인터페이스를 구현한다면 clone 함수를 통해 존재하는 객체의 사본을 생성할 수 있다.
사본을 생성하기 위해선 aCloneableObject.clone()를 사용해야 한다.
만약 clone함수가 호출된 객체가 Cloneable 인터페이스를 구현했다면 객체의 clone함수 구현이 새로운 객체를 생성하는데, 이 객체는 원본 객체와 클래스가 같고 원본 객체의 맴버 변수들과 같은 값으로 맴버들이 초기화 된다.
class를 cloneable 하는 가장 쉬운 방법은 class declaration에 Cloneable을 implement하는 것이다.
몇몇의 클래스들에게는 Object 클래스의 clone함수을 사용해도 올바르게 동작한다. 그러나 만약 객체가 외부의 객체를 참조하는 레퍼런스를 포함하고 있다면 clone함수를 override해 옮바른 방법으로 동작하게 구현해야한다.
그렇지 않을 경우 원본 객체와 clone객체가 독립적으로 외부 객체를 가지지않는다.
clone함수를 override하여 원본 객체는 원본 외부 객체를 참조하고, clone 객체는 clone 외부 객체를 참조하도록 해 독립성을 만족시켜야한다.
Object 클래스는 객체가 gc에 의해 제거됬을때 호출되는callback 함수인 finalize 함수를 지원한다.
Object 클래스의 finalize 함수 구현은 아무것도 하지 않는다. override해 자원을 free하는 cleanup작업으로 override할 수 있다.
finalize 메소드는 시스템에 의해 자동으로 호출 될 수 있지만 호출 될 지 안 될 지 불확실하다.
그러므로 이 함수가 cleanup을 해주길 바라면 안된다.
예를 들어 파일 디스크립터를 닫지않고 finalzie 함수가 대신 close하길 기대하면 파일 디스크럽트 공간이 부족해질 수 있다.
You cannot override getClass.
항상 toString 함수를 override 하는 것을 염두해야 한다.
Object의 toString 함수는 String으로 표현한 객체를 반환한다.
디버깅에 매우 효과적
String으로 표현한 객체는 객체에 전적으로 달려있어 override해야한다.
추상 클래스는 인터페이스와 비슷하다.
인스턴스화 할 수 없고, 구현이 된 함수와 안된 함수를 포함하고 있다.
추상 클래스
인터페이스
클래스는 1개만 extend 가능하지만 인터페이스는 여러개 implement 가능
어떤 것을 사용해야 할까?
추상 클래스 사용을 고려해야할 경우들
인터페이스 사용을 고려해야할 경우들
AbstractMap 클래스가 추상 클래스의 예이다.
HashMap 클래스는 여러 인터페이스를 구현한다.