부모클래스에 age라는 정수형 변수를 멤버변수로 추가하면,
자손 클래스는 조상의 멤버로 상속받기 때문에, 자식클래스는 자동적으로
age라는 멤버변수가 추가된 것과 같은 효과를 얻는다.
반면 자식클래스에 새로운 멤버로 play()메서드를 추가했을시엔
부모클래스는 아무런 영향도 받지않는다.
따라서 자식클래스는 조상 클래스의 모든 멤버를 상속 받으므로 항상 조상 클래스보다
같거나 많은 멤버를 갖는다. 즉, 상속에 상속을 거듭할수록 상속받는 클래스의 멤버 개수는
점점 늘어나게 된다.
생성자와 초기화 블럭은 상속되지 않는다.??
자식 클래스의 인스턴스를 생성하면 조상 클래스의 멤버도 함께 생성되기 때문에 따로 조상 클래스의
인스턴스를 생성하지 않고도 조상 클래스의 멤버들을 사용할 수 있다.
즉, 자손 클래스의 인스턴스를 생성하면 조상 클래스의 멤버와 자손 클래스의 멤버가 합쳐진
하나의 인스턴스로 생성된다.
조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
ex)Class Parent{
void parentMethod() throws IOException, SQLException{
}
}
Class Child extends Parent{
void parentMethod() throws IOException{
}
}
ex)
Class Child extends Parent{
void parentMethod() throws Exception{
}
}
이것은 부모클래스보다 갯수는 적게 선언했지만,
범위가 크므로 하나만 선언한 것 이 아니다.
따라서 부모클래스보다 갯수도 적으면서 범위도 좁아야한다.
------------------------------------------------------------
오버로딩 - 기존에 없는 새로운 메서드를 정의하는 것.
동일이름이지만 매개변수의 갯수나, 타입이 다른 새로운 메서드를
정의하는것.
오버라이딩 - 조상으로부터 그대로 상속받아 내용만 변경하는 것.
-----------------------------------------------------------
super
조상의 멤와 자신의 멤버를 구별하는데 사용된다는 점을 제외하고는 super와
this는 근복적으로 같다. 모든 인스턴스메서드에는 자신이 속한
인스턴스의 주소가 지역변수로 저장되는데, 이것이 참조변수인 this와 super의 값이된다.
static메서드(클레스메서드)는 인스턴스와 관련이 없다. 그래서 this와 마찬가지로
super역시 staic메서드에서는 사용할 수 없고 인스턴스메서드에서만 사용할 수 있다.
public class SuperTest {
public static void main(String args[]) {
Child c = new Child();
c.method();
}
}
class Parent {
int x = 10;
}
class Child extends Parent {
void method() {
System.out.println("x=" + x);
System.out.println("this.x=" + this.x);
System.out.println("super.x=" + super.x);
}
}
이경우 Child Class에 변수x가 없어도 자식클래스는 부모클래스의 멤버변수를
포함하고 있기때문에 x가 출력이 되는것이다.
게다가 this.x또한 자식클래스에 없으므로 부모클래스의 x를 찾게되는것이다.
super는 원래 부모꺼를 찾는다.
public class SuperTest {
public static void main(String args[]) {
Child c = new Child();
c.method();
}
}
class Parent {
int x = 10;
}
class Child extends Parent {
int x = 5;
void method() {
System.out.println("x=" + x);
System.out.println("this.x=" + this.x);
System.out.println("super.x=" + super.x);
}
}
이경우엔 부모클래스에도 x가있고 자식클래스에도 x가있다.
이경우에 자식클래서 x를 출력하면 자신(자식클래스)의 클래스의
x를 출력하게되고 this또한 자신(자식클래스)의 클래스의 x를 가리키게된다.
여전히 super는 부모클래스의 x를 가리킨다.
super() - 조상 클래스의 생성자
자식 클래스의 인스턴스를 생성하면, 자손의 멤버와 조상의 멤버가 모두 합쳐진
하나의 인스턴스가 생성된다. 그래서 자손 클래스의 인스턴스가 조상클래스의 멤버들을
사용할 수 있는 것이다.
이 때 조상 클래스 멤버의 생성과 초기화 작업이 수행되어야 하기 때문에 자손 클래스의
생성자에서 조상 클래스의 생성자가 호출 되어야한다.
생성자의 첫 줄에서 조상클래스의 생성자를 호출해야하는 이유는 자손 클래스의 멤버가
조상 클래스의 멤버를 사용할 수도 있으므로 조상의 멤버들이 먼저 초기화되어 있어야
하기 때문이다.
이와 같은 조상 클래스 생성자의 호출은 클래스의 상속관계를 거슬러 올라가면서
계속 반복된다. 마지막으로 모든 클래스의 최고 조상인 Object클래스의 생성자인
Object()까지 가서야 끝이 난다.
그래서 Object클래스를 제외한 모든 클래스의 생성자는 첫 줄에 반드시 자신의
다른 생성자 또는 조상의 생성자를 호출해야한다. 그렇지 않으면 컴파일러는
생성자의 첫 줄에 'super()'를 자동적으로 추가할 것이다.
public class PointTest {
public static void main (String [] args){
Point3D p3 = new Point3D(1,2,3);
}
}
class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
String getLocation() {
return "x :" + x + ", y:" + y;
}
}
class Point3D extends Point {
int z;
Point3D(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
}
이것은 컴파일에러가 발생한다.
이유는 Point3D의 객체를 만들때 Point3D의 생성자를 호출한다.
이때 생성자 첫줄에 다른 생성자를 호출하지 않기 때문에 컴파일러가
super()를 삽입한다.
그러나 Point3D의 조상인 Point클래스에는 default생성자인
Point()가 없기 때문에 컴파일이 발생한다.
default생성자는 어떠한 생성자가 정의되어 있을시엔 자동 생성이되지않는다.
public class PointTest {
public static void main(String[] args) {
Point3D p3 = new Point3D(1, 2, 3);
}
}
class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
String getLocation() {
return "x :" + x + ", y:" + y;
}
}
class Point3D extends Point {
int z;
Point3D() {
this(1,2,3);
}
Point3D(int x, int y, int z) {
super(1, 2);
this.x = x;
this.y = y;
this.z = z;
}
}
이런식으로 객체 생성시 Point3D(int x, int y, int z) 생성자를
호출하고, 그안에서 부모 생성자 Point(int x, int y))를 호출해주도록
super(1,2)를 정의해줬기때문에 컴파일 에러가 나지 않는다.
Point3D()생성자는 super가 생략이 된것이아니라,
생성자를 호출하였기때문에(super의 것들을)건드리지 않았기때문에(토스한다는개념)
컴파일 에러가 뜨지 않는것이다.
결국엔 생성자의 호출은 계속 이어져서 결국 Object클래스의 생성자인
Object()까지 호출되어야 끝나는 것이다.