오버라이딩(overriding)
- 상속받은 조상의 메서드를 자신에 맞게 변경하는 것(메서드 오버라이딩)
- 선언부는 변경불가, 내용(구현부)만 변경 가능
예제1) Point 조상 클래스의 getLoction( )을 Point3D 클래스가 오버라이딩
getLocation은 원래 x와 y의 값만 나타내지만 Point3D가 오버라이딩이 되어서 x,y,z값이 나타나게 된다!
class Point {
int x;
int y;
String getLocation() {
return "x:" + x + ", y:" + y;
}
}
class Point3D extends Point {
int z;
String getLoction() { // 조상의 getLocation()을 오버라이딩
return "x:" + x + ", y:" + y + ", z:" + z;
}
}
예제2) 모든 클래스의 조상인 Object클래스의 toString( )메서드를 사용해서 x와 y값을 넣고 출력!
생성자를 사용해서 굳이 x와 y를 따로 초기화해주지 않아도 한 줄의 코드로 x와 y의 값을 나타낼 수 있다.
class Point {
int x;
int y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
// Object클래스의 toString()을 오버라이딩
public String toString() {
return "x:" + this.x + ", y:" + this.y; //this 참조변수 생략 가능
}
}
public class Inherit2 {
public static void main(String[] args) {
Point p = new Point(3,5); // Point 생성자 생성!
// p.x = 3;
// p.y = 5;
// System.out.println("x:" + p.x + ", y:" + p.y); //x:3, y:5
System.out.println(p); //x:3, y:5
// System.out.println(p.toString()); //x:3, y:5
}
}
오버라이딩의 조건
1. 선언부가 조상 클래스의 메서드와 일치해야 한다. (선언부: 반환타입, 메서드 이름, 매개변수 목록)
2. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
접근제어자: public protected default point
- 만약 조상 클래스에 정의된 메서드의 접근 제어자가 protected -> 이를 오버라이딩 하는 자손 클래스의 메서드는 접근제어자가 protected나 public이어야 한다. (접근제어자의 범위: Public > Protected > (default) > private)
3. 자손클래스의 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.
-> 조상 클래스인 Parent는 예외선언 2개 자손 클래스인 Child는 예외선언 1개
4. 인스턴스메서드를 static메서드로 또는 그 반대로 변경할 수 없다.
- static 멤버들은 자신들이 정의된 클래스에 묶여있다! 각 메서드는 클래스이름으로 구별될 수 있고, 호출할 때는 참조변수.메서드( )이름 대신 '클래스이름.메서드이름( )'으로 하는 것이 바람직하다.
오버로딩과 오버라이딩
- 오버로딩과 오버라이딩은 관계 없음(생성자 this( )와 참조변수 this 같이)
오버로딩(overloading) | 오버라이딩(overriding) |
기존에 없는 새로운 메서드를 정의하는 것(new) -> 이름이 같음 |
상속받은 메서드의 내용을 변경하는 것(change, modify) |
상속과 관계없음 | 상속과 관계 있음 |
class Parent {
void parentMethod() {}
}
class Child extends Parent {
void parentMethod() {} // 오버라이딩
void parentMehhod(int i) {} // 오버로딩, Child안에 이미 같은 이름인 메서드가 있고 매개변수만 다름)
void childMethod() {} // 메서드 정의
void childMehthod(int i) {} // 오버로딩, child안에 이미 같은 이름인 메서드가 있고 매개변수만 다름)
//void childMethod() {} // 중복정의 에러!
}
참조변수 super
- 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수(객체 자신을 가리키는 참조변수)
- 인스턴스 메서드(생성자) 내에만 존재(static 메서드 내에서 사용 불가)
- 조상 멤버를 자신의 멤버와 구별할 때 사용(참조변수 this는 lv와 iv 구별에 사용)
- 조상 멤버는 super 참조변수 사용하고 자신의 멤버는 this 참조변수 사용
예제1) Parent 클래스와 Child 클래스 둘 다 같은 int x 변수가 있는 경우
public class InheritSuper {
public static void main(String args[]) {
Child child = new Child();
child.method();
}
}
class Parent { int x = 10; }
class Child extends Parent { //멤버 3개
int x = 20;
void method() {
System.out.println("x = " + x); // 가까운 쪽 클래스의 x
System.out.println("this.x = " + this.x); // Child 클래스의 x
System.out.println("super.x = " + super.x); // Parent 조상클래스의 x
}
}
<출력값>
x = 20
this.x = 20
super.x = 10
예제2) Child클래스에는 x변수가 없고 Parent 클래스에만 int x 변수가 있는 경우
public class InheritSuper {
public static void main(String args[]) {
Child child = new Child();
child.method();
}
}
class Parent { int x = 10; } // super.x와 this.x둘 다 가능!
class Child extends Parent { //멤버 2개
void method() {
System.out.println("x = " + x); // Parent 클래스의 x
System.out.println("this.x = " + this.x); // Parent 클래스의 x
System.out.println("super.x = " + super.x); // Parent 클래스의 x
}
}
<출력값>
x = 10
this.x = 10
super.x = 10
-> this, super 둘 다 같은 주소를 가리키고 있음
예제3) 조상 클래스의 메서드를 자손 클래드에서 오버라이딩 한 경우에 super 사용 가능하다.
class Parent {
int x;
int y;
String getLocation() {
return "x : " + x + ", y : " + y;
}
class Child extends Parent {
int z;
// 오버라이딩
String getLocation() {
return super.getLoction() + ", z : " + z; // 조상의 메서드 호출
}
}
- 조상 클래스의 메서드의 내용에 추가적으로 작업을 덧붙이는 경우라면 super를 사용해서 조상클래스의 메서드를 포함시키는 것이 좋음
-> 나중에 조상클래스에서 메서드가 변경되도라도 그 내요이 자손클래스의 메서드에 자동적으로 반영될 것
super( ) – 조상의 생성자
- 조상클래스의 생성자를 호출할 때 사용
- 조상의 멤버는 조상의 생성자를 호출해서 초기화
- 참조변수 super와 관계없음
- 조상인 Point 클래스가 iv를 초기화하고 있음
-> 자손의 생성자는 자기가 선언한 것만 초기화한다!(조상의 멤버를 굳이 초기화할 필요 없음)
-> 안 좋은 코드이다!!
-> 코드를 이렇게 바꿔야 함
-> 조상클래스의 생성자가 조상멤버를 초기화하게 해야 함
super( ) – 조상의 생성자 추가 조건
- 생성자의 첫 줄에 반드시 생성자를 호출해야 한다. 그렇지 않으면 컴파일러가 생성자의 첫 줄에 super( );를 삽입(첫 줄에 반드시 super( );를 적어줘야 한다!)
-> 생성자의 첫 줄에서 조상클래스의 생성자를 호출해야하는 이유는 자손 클래스의 멤버가 조상 클래스의 멤버를 사용할 수 있으므로 조상의 멤버들이 먼저 초기화되어 있어야 함
class Point extends Object {
int x;
int y;
Point() {
this(0,0);
}
Point(int x, int y) {
super(); // 조상인 Object 클래스의 기본 생성자 호출
this.x = x;
this.y = y;
}
}
예제 Point 조상 클래스와 Point3D 자식 클래스(모든 생성자는 다른 모든 생성자는 다른 생성자를 호출해야 한다는 조건)
class Point {
int x;
int y;
Point(int x, int y) {
super(); // 컴파일러가 자동 추가(, Point의 조상인 Object 클래스 생성자
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) {
super(x, y); // 조상의 생성자 Point(int x, int y)를 호출 아니면 super( ) 이렇게 적어도 됨
// this.x = x;
// this.x = y;
this.z = z;
}
String getLocation() { // 오버라이딩
return "x: " + x + "y: " + y + "z: " + z;
}
}
'멀티캠퍼스 풀스택 과정 > Java의 정석' 카테고리의 다른 글
자바의 정석3-4 제어자(static, final, abstract, 접근제어자) (0) | 2022.01.01 |
---|---|
자바의 정석3-3 패키지와 import문 (0) | 2022.01.01 |
자바의 정석3-1 상속(Inheritance)과 포함(composite) (0) | 2022.01.01 |
자바의 정석2-8 변수의 초기화, 멤버변수(iv,cv)의 초기화 (0) | 2021.12.31 |
자바의 정석2-7 생성자 (생성자 this( ), 참조변수this) (0) | 2021.12.31 |