부모 멤버에 이미 a()라는 메서드가 존재한다면 자식 객체 생성시, 부모 생성자가 먼저 호출되기 때문에 부모 클래스의 a()가 먼저 메모리에 올라간다. 그 다음 자식 멤버를 정의할 때, a()라는 메서드를 선언하면 기존에 만들어진 부모의 a() 메서드에 자식에서 작성한 메서드 내용이 덮어 씌워진다. 따라서 자식 객체로 a() 메서드를 사용하면 재정의된 기능으로 사용하게 된다.
오버라이딩의 조건
오버라이딩 할 때 유의사항
public class Main {
public static void main(String[] args) {
B b = new B();
b.age = 20;
b.ageUp();
System.out.println(b.age); // 22
}
}
class A {
String name;
int age;
int ageUp() {
return ++age;
}
}
class B extends A {
@Override
int ageUp() {
age += 2;
return age;
}
}
위의 코드를 보자. B는 A를 상속받고 있고 A의 정의된 ageUp() 메서드를 오버라이딩 하고 있다. 따라서 main 메서드에서 B 타입의 객체 b를 만들어서 b.ageUp() 메서드를 사용하면 재정의한대로 사용되는 것이다.
super는 자식 클래스에서 부모 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수이다.
public class Main {
public static void main(String[] args) {
B b = new B();
b.print(); // 파이썬
// 30
// 자바
// 20
}
}
class A {
String name = "자바";
int age = 20;
}
class B extends A {
String name = "파이썬";
int age = 30;
void print() {
System.out.println(this.name);
System.out.println(this.age);
System.out.println(super.name);
System.out.println(super.age);
}
}
위의 코드를 보자. A 클래스에서 name과 age가 각각 "자바", 20으로 할당되어 있고, B 클래스에서 name과 age가 각각 "파이썬", 30으로 할당되어 있다. 그리고 B는 A를 상속받고 있다.
그리고 B에는 print라는 메서드가 정의되어 있는데
this.name과this.age,그리고super.name과super.age를 출력하는 메서드이다. 여기서this.키워드는 그 클래스의 멤버변수를 의미하기 떄문에this.name과this.age는 각각 B 클래스의 멤버변수인 "파이썬"과 30을 의미한다. 그리고super.키워드는 부모클래스인 A 클래스의 멤버변수를 의미하므로super.name과super.age는 각각 A 클래스의 멤버변수인 "자바"와 20을 의미한다.
super()는 조상 클래스의 생성자를 호출하는데 사용된다.
자식 클래스의 객체는 자식 생성자를 호출하여 객체화를 진행하는데, 메모리에 자식 클래스의 필드만 올라갔다면 자식 객체는 절대 부모 클래스에 선언되어 있는 필드에 접근할 수 없다. 따라서 자식 생성자를 호출하게 되면 상속받고 있는 클래스가 있는지 확인 후 부모의 생성자가 자동으로 먼저 호출이 된다. 즉, 자식 클래스의 생성자 첫 줄에는 항상 super()가 호출된다. 명시적으로 적지 않더라도 컴파일러가 자동적으로 super();을 생성자의 첫 줄에 삽입한다.
public class Main {
public static void main(String[] args) {
Point3D p = new Point3D(5, 4, 1);
System.out.println(p.getLocation()); // ( 5, 4, 1 )
}
}
class Point{
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
String getLocation() {
return "( " + x + ", " + y + " )";
}
}
class Point3D extends Point{
int z;
public Point3D(int x, int y, int z) {
super(x, y);
this.z = z;
}
@Override
String getLocation() {
return "( " + x + ", " + y + ", " + z + " )";
}
}
위의 코드를 보자. Point 클래스에는 변수 x와 y 그리고 메소드 getLocation()이 정의되어있다. 그리고 Point3D 클래스에는 변수 z와 메소드 getLocation()가 오버라이딩되어 있다.
그리고 Point 클래스의 생성자는 x와 y를 매개변수로 받아와 멤버변수 멤버변수 x와 y에 대입한다. 그리고 Point3D 클래스의 생성자는 x, y, z를 매개변수로 받아와 부모클래스의 생성자를 호출하고 z를 멤버변수 z에 대입한다. 이때 호출된 부모클래스의 생성자에서도 역시 매개변수 x와 y의 값을 각각 멤버변수 x와 y에 대입할 것이다.
따라서 main 메서드에서 매개변수로 5, 4, 1을 넘겨주며 Point3D 타입의 객체 p를 생성했을 때, 멤버변수 x, y, z에 각각 5, 4, 1이 대입되어 출력이 잘 될것이다.