toString()
, equals(Object obj)
, hashCode()
...)class Tv {} // 이 클래스는 자동적으로 Object 클래스를 상속받는다.
class Tv extends Object {} // 같은 코드
class SmartTv extends Tv {}
"클래스이름@객체의 주소"
public class Ex7_1 {
public static void main(String args[]) {
Point2D p2 = new Point2D();
Point3D p3 = new Point3D();
p2.x = 1;
p2.y = 2;
p3.x = 3;
p3.y = 4;
p3.z = 5;
System.out.println(p2.toString()); // Point2D@28d93b30
System.out.println(p2); // Point2D@28d93b30
System.out.println(p3.toString()); // Point3D@1b6d3586
System.out.println(p3); // Point2D@28d93b30
}
}
class Point2D { // extends Object
int x;
int y;
}
class Point3D extends Point2D {
int z;
}
상속받은 조상의 메서드를 자신에 맞게 변경하는 것
규칙
- 선언부가 조상 클래스의 메서드와 일치해야 한다.(반환값, 이름, 인자)
- 접근 제어자(
public, protected, private, default
)를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.- 예외(
throws
)는 조상 클래스의 메서드보다 많이 선언할 수 없다.
public class Ex7_1 {
public static void main(String args[]) {
Point2D p2 = new Point2D();
Point3D p3 = new Point3D();
p2.x = 1;
p2.y = 2;
p3.x = 3;
p3.y = 4;
p3.z = 5;
System.out.println(p2.getLocation());
System.out.println(p3.getLocation());
}
}
class Point2D {
int x;
int y;
String getLocation(){
return "(x,y) : " + "(" + x + "," + y + ")";
}
}
class Point3D extends Point2D {
int z;
String getLocation(){ // 오버라이딩
return "(x,y,z) : " + "(" + x + "," + y + ","+ z + ")";
}
}
Point2D
의 메서드를 Point3D
가 사용하면 z가 빠지게 됩니다.
따라서 오버라이딩을 통해 Point3D
일 때는 z를 포함한 getLocation()
메서드를 작성해 주어야 합니다.
오버라이딩을 Object의 메서드에 활용할 수 있습니다.
public class Ex7_1 {
public static void main(String args[]) {
Point2D p2 = new Point2D();
Point3D p3 = new Point3D();
p2.x = 1;
p2.y = 2;
p3.x = 3;
p3.y = 4;
p3.z = 5;
System.out.println(p2);
System.out.println(p3);
}
}
class Point2D {
int x;
int y;
// Object의 toString() 메서드 오버라이딩
public String toString(){
return "(x,y) : " + "(" + x + "," + y + ")";
}
}
class Point3D extends Point2D {
int z;
// Object의 toString() 메서드 오버라이딩
public String toString(){
return "(x,y,z) : " + "(" + x + "," + y + ","+ z + ")";
}
}
public을 붙인 이유: 오버라이딩을 할 때 선언부는 똑같이 작성해야 합니다.
오버로딩 vs 오버라이딩
- 오버로딩: 기존에 없는 새로운 메서드를 정의하는 것(단 같은 클래스 내에 이름이 같은 메서드)
- 오버라이딩: 상속받은 메서드의 내용을 변경하는 것
class Parent {
void parentMethod() {}
}
class Child extends Parent {
void parentMethod() {} // 오버라이딩
void parentMethod(int i) {} // 오버로딩
void childMethod() {} // 메서드 정의
void childMethod(int i) {} // 오버로딩
void childMethod() {} // 에러(중복 정의)
}
super, this의 차이점
super : 조상멤버와 자손멤버를 구별할 때 사용
this : 지역변수와 인스턴스 변수를 구별할 때 사용
public class Test {
public static void main(String args[]) {
MyChild mc = new MyChild();
mc.method();
}
}
class MyParent {
int x = 20;
}
class MyChild extends MyParent {
int x = 10;
void method() {
System.out.println(super.x); // super.x = 20
System.out.println(this.x); // this.x = 10
}
}
만약 MyChild 클래스에 x 변수가 없다면..
자손멤버와 조상멤버를 따로 구별할 이유가 없기 때문에 자손멤버의 x도 조상의 변수를 상속받습니다.
super.x = 20
, this.x = 20
으로 같습니다.
조건
- 생성자의 첫 줄에 반드시 생성자를 호출해야 한다!!(중요)
- 그렇지 않으면 컴파일러가 생성자의 첫 줄에
super();
를 삽입
class MyPoint2D{
int x,y;
MyPoint2D(int x, int y){
this.x = x;
this.y = y;
}
}
// super() 사용
class MyPoint3D extends MyPoint2D{
int z;
MyPoint3D(int x, int y, int z){
super(x,y); // 조상 클래스의 생성자를 호출 - MyPoint2D(int x, int y)
this.z = z;
}
}
// 직접 초기화
class MyPoint3D extends MyPoint2D{
int z;
MyPoint3D(int x, int y, int z){
// super(); 컴파일러가 이 코드를 자동으로 생성한다.
this.x = x;
this.y = y;
this.z = z;
}
}
조상의 멤버는 조상의 생성자(super()
)로 초기화하는 것이 좋은 방법입니다.