본문 바로가기
멀티캠퍼스 풀스택 과정/Java의 정석

자바의 정석3-2 오버라이딩, super 참조변수, super( ) 생성자

by 이쟝 2022. 1. 1.

오버라이딩(overriding)

- 상속받은 조상의 메서드를 자신에 맞게 변경하는 것(메서드 오버라이딩)

- 선언부는 변경불가, 내용(구현부)만 변경 가능

 


예제1) Point 조상 클래스의 getLoction( )을 Point3D 클래스가 오버라이딩

getLocation은 원래 xy의 값만 나타내지만 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( )메서드를 사용해서 xy값을 넣고 출력!

 

생성자를 사용해서 굳이 xy를 따로 초기화해주지 않아도 한 줄의 코드로 xy의 값을 나타낼 수 있다.

 

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 메서드 내에서 사용 불가)

- 조상 멤버자신의 멤버와 구별할 때 사용(참조변수 thislviv 구별에 사용)

- 조상 멤버는 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;
	}
}