[Java] Ch07_2. 오버라이딩(overriding)

토끼는 개발개발·2022년 1월 23일
0

Java

목록 보기
22/29
post-thumbnail

Chapter07. 객체지향 프로그래밍Ⅱ


✏️ 2. 오버라이딩(overriding)


2.1 오버라이딩이란?

부모 클래스로부터 상속받은 메서드의 내용을 변경하는 것을 오버라이딩이라고 한다.

2차원 좌표계의 한 점을 표현하기 위한 Point클래스가 있을 때, 이를 부모로 하는 Point3D클래스, 3차원 좌표계의 한 점을 표현하기 위한 클래스를 다음과 같이 새로 작성하였다고 하자.

class point {
	int x;
    	int y;
        
        String getLocation() {
        	return "x :" + x + ", y :"+y;
        }
}

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

Point클래스의 getLocation()은 한 점의 x, y 좌표를 문자열로 반환하도록 작성되었다.
Point3D클래스는 getLocation()을 상속받아 자신에 맞게 z축의 좌표값도 포함하여 반환하도록 오버라이딩 하였다.

Point클래스를 사용하던 사람들은 새로 작성된 Point3D클래스가 Point클래스의 자식클래스이므로 getLocation()을 호출하면 Point클래스가 그랬듯이 점의 좌표를 문자열로 얻을 수 있을 것이라고 기대할 것이다. 이것이 새로운 메서드가 아닌 오버라이딩을 하는 이유이다.




2.2 오버라이딩의 조건

부모 클래스에서 오버라이딩하는 메서드는 부모 클래스의 메서드와

  • 이름이 같아야 한다.
  • 매개변수가 같아야 한다.
  • 반환타입이 같아야 한다.

한마디로 요약하면 선언부가 서로 일치해야 한다는 것이다. 다만 접근 제어자와 예외는 제한된 조건 하에서만 다르게 변경할 수 있다.


▶ 오버라이딩 주의점

1. 접근 제어자는 부모 클래스의 메서드보다 좁은 범위로 변경 할 수 없다.
2. 부모 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
3. 인스턴스메서드를 static메서드로 또는 그 반대로 변경할 수 없다.

만일 부모 클래스에 정의된 메서드의 접근 제어자가 protected라면, 이를 오버라이딩하는 자식 클래스의 메서드는 접근 제어자가 protected나 public이어야 한다. 대부분의 경우 같은 범위의 접근 제어자를 사용한다.

접근 제어자의 접근범위를 넓은 것부터 나열하면 public, protected, (default), private이다.




2.3 오버로딩 vs. 오버라이딩

오버로딩(overloading) : 기존에 없는 새로운 메서드를 정의하는 것(new)
오버라이딩(overriding) : 상속받은 메서드의 내용을 변경하는 것(change, modify)

class Parent {
	void parantMethod() {}
}

class Child extends Parent {
	void parentMethod() {} // 오버라이딩
    	void parentMethod(int i) {} // 오버로딩
    	
        void childMethod() {}
        void childMethod(int i) {} // 오버로딩
        void childMethod() {} // 에러. 중복정의 되었음(already defined in Child)
}
    



2.4 super

super는 자식 클래스에서 부모 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수이다.

멤버변수와 지역변수의 이름이 같을 때 this를 붙여서 구별했듯이 상속받은 멤버와 자신의 멤버와 이름이 같을 때는 super를 붙여서 구별할 수 있다. 부모 클래스로부터 상속받은 멤버도 자식 클래스 자신의 멤버이므로 super대신 this를 사용할 수 있다. 그래도 부모 클래스의 멤버와 자식 클래스의 멤버가 중복 정의되어 서로 구별해야하는 경우에만 super를 사용하는 것이 좋다.

모든 인스턴스메서드에는 자신이 속한 인스턴스의 주소가 지역변수로 저장되는데, 이것이 참조변수인 this와 super의 값이 된다.

static메서드(클래스메서드)는 인스턴스와 관련이 없다. 그래서 this와 마찬가지로 super역시 static메서드에서는 사용할 수 없고 인스턴스메서드에서만 사용할 수 있다.


▶ ✨ 예제 1


public class SuperTest2 {

	public static void main(String[] args) {
		Child c = new Child();
		c.method();

	}

}

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

위의 예제1에서 결과를 보면 알 수 있듯이 super.x는 부모 클래스로부터 상속받은 멤버변수 x를 뜻하며, this.x는 자손 클래스에 선언된 멤버변수를 뜻한다.

변수만이 아니라 메서드 역시 super를 써서 호출할 수 있다. 특히 부모 클래스의 메서드를 자식 클래스에서 오버라이딩한 경우에 super를 사용한다.




2.5 super() - 부모 클래스의 생성자

this()와 마찬가지로 super() 역시 생성자이다.
super()는 부모 클래스의 생성자를 호출하는데 사용된다.

자식 클래스의 인스턴스를 생성하면, 자식의 멤버와 부모의 멤버가 모두 합쳐진 하나의 인스턴스가 생성된다. 그래서 자식 클래스의 인스턴스가 부모 클래스의 멤버들을 사용할 수 있는 것이다.
이 때 부모 클래스 멤버의 초기화 작업이 수행되어야 하기 때문에 자식 클래스의 생성자에서 부모 클래스의 생성자가 호출 되어야 한다.

생성자의 첫 줄에서 부모 클래스의 생성자를 호출해야하는 이유는 자식 클래스의 멤버가 부모 클래스의 멤버를 사용할 수도 있으므로 부의 멤버들이 먼저 초기화되어 있어야 하기 때문이다.

이와 같은 부모 클래스 생성자의 호출은 클래스의 상속관계를 거슬러 올라가면서 계속 반복된다. 마지막으로 모든 클래스의 최고 조상인 Object클래스의 생성자인 Object()까지 가서야 끝이난다.

그래서 Object클래스를 제외한 모든 클래스의 생성자는 첫 줄에 반드시 자신의 다른 생성자 또는 부모의 생성자를 호출해야 한다. 그렇지 않으면 컴파일러는 생성자의 첫 줄에 'super();'를 자동적으로 추가할 것이다.

Point3D(int x, int y, int z) {
	super();
    	this.x = x;
        this.y = y;
        this.z = z;
}

super()는 Point3D클래스의 조상인 Point클래스의 기본 생성자인 Point()를 뜻하므로 Point()가 호출된다.

Point3D() -> Point(int x, int y) -> Object()



참고
자바의 정석(저자: 남궁성)


오늘의 한 줄

오버라이딩과 오버로딩이 헷갈리지 않도록 주의해야겠다. 비슷한 단어와 개념들이 나오고 객체지향에 대해 알아갈수록 코드를 작성할 때 헷갈릴 것 같다.
개념이 익숙해지도록 실습이 많이 필요하고, 복습도 많이 해야겠다.

다음은 package와 import에 대해 공부하겠다.

profile
하이 이것은 나의 깨지고 부서지는 샏 스토리입니다

0개의 댓글