Java/객체지향

[객체지향][자바의 정석] - 7.2 오버라이딩(Overriding)

얄루몬 2021. 11. 8. 20:31

7.2 오버라이딩(Overriding)

 

 

 

1. 오버라이딩(overriding)이란?

- 조상 클래스로부터 상속받은 메서드의 내용을 상속받는 클래스에 맞게 변경하는 것을 의미한다.

- 상속받은 조상 메서드를 자신에 맞게 변경하는 것

class Point{
    int x;
    int y;
    // 받은 좌표를 문자열로 얻는 메소드
    String getLocation(){
        return "x: " + x + ", y : "+ y;
    }
}
class Point3D extends Point{
    int z;
    
    //선언부는 변경 불가, 구현부{ }는 변경 가능
    String getLoString(){ //오버라이딩 z를 포함시켜 고치는 것
        return "x: " + x + ", y : "+ y+", z : " + z;
    }
}

 

class MyPoint3{
    int x;
    int y;

    String getLocation(){
        return "x: " + x + ", y : "+ y;
    }
}
class MyPoint3D extends MyPoint3{
    int z;
    String getLocation(){ //오버라이딩
        return "x: " + x + ", y : "+ y + ", z : " + z;
    }
}

public class overrideTest1 {
	public static void main(String[] args) {
		MyPoint3D p = new MyPoint3D();
        p.x =3 ;
        p.y = 5;
        p.z = 7;
        System.out.println(p.getLocation());

	}

}

<조상으로부터 상속 받은 내용을 Overriding 한 코드>

 

 

class MyPoint3_2 extends Object{
	int x;
	int y;
	
	//Object 클래스의 toString()을 오버라이딩
	public String toString(){
		return "x: " + x + ", y : "+ y;
		 }
}

public class overridingTest2 {
	public static void main(String[] args) {
		MyPoint3_2 p = new MyPoint3_2();
		p.x=3;
		p.y=5;
		System.out.println(p.toString());
	}

}

<오브젝트 클래스를 오버라이딩한 코드>

 

 

class MyPoint3_2 extends Object{
	int x;
	int y;
	
	//Object 클래스의 toString()을 오버라이딩
	public String toString(){
		return "x: " + x + ", y : "+ y;
		 }
}

public class overridingTest2 {
	public static void main(String[] args) {
		MyPoint3_2 p = new MyPoint3_2();
		p.x=3;
		p.y=5;
		//System.out.println(p.toString());
        System.out.println(p);
	}

}

<오브젝트 클래스를 오버라이딩한 코드 2 (더 간략하게)>

 

 

class MyPoint3_2 extends Object{
	int x;
	int y;
	MyPoint3_2(int x, int y){
		this.x = x;
		this.y = y;
	}
	//Object 클래스의 toString()을 오버라이딩
	public String toString(){
		return "x: " + x + ", y : "+ y;
		 }
}

public class overridingTest2 {
	public static void main(String[] args) {
		MyPoint3_2 p = new MyPoint3_2(3,5);
		System.out.println(p);
	}

}

<오브젝트 클래스를 오버라이딩한 코드 3>

2. 오버라이딩의 조건

① 선언부가 같아야 한다. (이름, 매개변수, 리턴타입)

② 접근제어자를 좁은 범위로 변경할 수 없다 (접근제어자 - public, protected, private, default)

    - 조상의 메서드가 protected라면, 범위가 같거나 넓은 protected나 public으로만 변경할  수 있다.

③ 조상클래스의 메서드보다 많은 수의 예외를 선언할 수 없다. - 8장에서 배움 외우기

import java.io.IOException;
import java.sql.SQLException;

class Parent{
    void parentMethod() throws IOException, SQLException {
        // ... 
    }
}

class Child extends Parent {
    void parentMethod() throws IOException{

    }
}
class Child2 extends Parent {
    void parentMethod() throws Exception {
    }
}

 

 

3. 오버로딩 VS 오버라이딩

오버로딩(Overloading) - 기존에 없는 새로운 메서드를 정의하는 것(new) ---> 상속과 관계 없음
오버라이딩(Overriding) - 상속받은 메서드의 내용을 변경하는 것(change, modify) ---> 상속과 관계 있음
class Parent{
    void parentMethod() {

    }
}
class Child extends Parent {
    void parentMethod(){ } // 오버라이딩
    void parentMethod(int i) { } // 오버로딩


    void childMethod() {} // 오버로딩
    void childMethod(int i) //에러!! 중복정의 
    void childMethod() {}
}

둘은 이름만 비슷하고 전혀 관련이 없다.

 

4. Super - 참조변수(1)

- this : 인스턴스 자신을 가리키는 참조변수. 인스턴스의 주소가 저장되어 있고 모든 인스턴스 메소드에 지역변수로 숨겨진 채로 존재한다. 또한 this는 지역변수와 인스턴스변수 구별에 사용된다. 

 

-super : this와 같다. 조상의 멤버와 자신의 멤버를 구별하는 데 사용한다. static 메서드에서는 사용불가하다. 

class Parent{
    int x = 10;
}

class Child extends Parent{
    int x = 20;
    void method(){
        System.out.println("x="+x);
        System.out.println("this.x="+this.x);
        System.out.println("super.x="+super.x);
    }
}

 

 

4. Super - 참조변수(2)

▶ this - 인스턴스 자신을 가리키는 참조변수. 인스턴스의 주소가 저장되어있다. 모든 인스턴스 메서드에 지역변수로 숨겨진 채로 존재한다.

super - this와 같다. 조상의 멤버와 자신의 멤버를 구별하는 데 사용한다.

 

super와 this가 다른 주소를 가리키는 경우 

//참조변수 super
public class super1 {
	public static void main(String[] args) {
		Child c = new Child();
		c.method();
	}
}

class Parent {int x = 10;}

class Child extends Parent{
	int x = 20; //this.x 
	
	void method() {
		System.out.println("x=" + x); //20
		System.out.println("this.x=" + this.x); //20 자기 멤버
		System.out.println("super.x=" + super.x); //10 조상멤버
	}
}

 

super와 this가 같은 주소를 가리키는 경우 

//참조변수 super
public class super2 {
	public static void main(String[] args) {
		Child2 c = new Child2();
		c.method();
	}
}

class Parent2 {int x = 10;} // super.x this.x 둘 다 가능 

class Child2 extends Parent2{

	void method() {
		System.out.println("x=" + x); //10 자신의 x가 없어서 x는 조상 멤버
		System.out.println("this.x=" + this.x); //10 조상멤버
		System.out.println("super.x=" + super.x); //10 조상멤버
	//x가 조상멤버에 하나밖에 없기 때문에 this와 super가 같은 곳을 가르킨다.
	
	}
}

 

4. super( ) - 조상의 생성자(1) 

- 자손클래스의 인스턴스를 생성하면, 자손의 멤버와 조상의 멤버가 합쳐진 하나의 인스턴스가 생성된다.

- 조상의 멤버들도 초기화되어야 하기 때문에 자손의 생성자의 첫 문장에서 조상의 생성자를 호출해야 한다.

Object 클래스를 제외한 모든 클래스의 생성자 첫 줄에는 생성자(같은 클래스의 다른 생성자 또는 조상의 생성자)를 호출해야 한다.
그렇지 않으면 컴파일러가 자동적으로 'super( );'를 생성자의 첫 줄에 삽입한다.

생성자, 초기화블럭 -> 상속 X

<에러가 나는 경우>

class Point{
	int x,y;

	Point(int x, int y){
		this.x = x;
		this.y = y;
	}
}

class Point3D extends Point {
	int z;
	
	Point3D(int x, int y int z) {
		this.x = x; //조상의 멤버 초기화 -> 에러
		this.y = y; //조상의 멤버 초기화 -> 에러
		this.z = z; //자손은 자신의 멤버만 초기화해야 한다. 
	}
}

 

<조상의 멤버 초기화 없이 조상의 생성자를 호출하는 법>

class Point{
	int x,y;

	Point(int x, int y){
		this.x = x;
		this.y = y;
	}
}

class Point3D extends Point{
	int z;
	Point3D(int x, int y int z) {
		super(x,y); // 조상 클래스의 생성자 Point(int x, int y)를 호출
		this.z = z; //자신의 멤버를 초기화
	}
}

 

추가조건

- 생성자의 첫 줄에 반드시 생성자를 호출해야 한다. 그렇지 않으면 컴파일러가 생성자의 첫 줄에 super();를 삽입한다.

class Point {
    int x;
    int y;

    Point(){
        this(0,0);
    }
    Point(int x, int y){
        this.x=x;
        this.y=y;
    }
}

 

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;
    }
}

자식이 조상의 멤버를 초기화 하고 있기 때문에 에러가 나서 super(x, y)를 사용해서 생성자호출로 바꿔주어야 한다