공부/Java

[Java-07] 객체지향프로그래밍Ⅱ - 상속, 오버라이딩

줭♪(´▽`) 2021. 2. 22. 11:02

1. 상속(Inheritance)

1) 상속의 정의와 구현

- 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것

- 적은 양의 코드로 새로운 클래스를 작성할 수 있고 코드를 공통적으로 관리할 수 있음

- 코드의 추가 및 변경이 매우 용이함

- 코드의 재사용성을 높이고 코드의 중복을 제거하여 프로그램의 생산성과 유지보수에 크게 기여함

 

- 상속은 키워드 'extends'를 사용하여 구현함

 

class Child extends Parent {
   ...
}

 

조상 클래스 = 부모(parent)클래스, 상위(super)클래스, 기반(base)클래스
자손 클래스 = 자식(child)클래스, 하위(sub)클래스, 파생된(derived) 클래스

 

- 상속계층도(class hierarchy) : 클래스 간의 상속관계를 그림으로 표현한 것

 

class Parent {
    int age;
}

class Child extends Parent { 
    void play() {
    	System.out.println("play");
    }
}

 

 

두 클래스의 상속계층도

 

 

두 클래스의 다이어그램

 

 

- 조상 클래스(Parent)가 변경되면 자손 클래스(Child)는 영향을 받음

- 자손 클래스(Child)가 변경되어도 조상 클래스(Parent)는 영향을 받지 않음

 

- 자손 클래스의 멤버 개수는 조상 클래스보다 항상 같거나 많음

- 상속을 거듭할수록 상속받는 클래스의 멤버 개수는 점점 늘어남 (확장 = extend)

- 생성자와 초기화 블럭은 상속되지 않음 (멤버만 상속)

 

2) 포함(Compostie) 관계

- 상속 외에도 클래스를 재사용하는 방법으로 클래스 간에 '포함(Composite)'관계를 맺어주는 것이 있음

- 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것

 

class Point {
    int x;
    int y;
}

class Circle {
    //int x;
    //int y;
    Point c = new Point();	// x, y를 갖는 Point 클래스를 참조변수로 선언
    int r;
}

 

 

3) 상속관계과 포함관계의 구분

 

상속관계 : ~은 ~이다 (is-a)
포함관계 : ~은 ~을 가지고 있다. (has-a)

 

ex)

 

A Circle is a Shape. (O)

A Circle has a Shape. (X)

-> Circle은 Shape를 상속받음

 

A Circle is a Point. (X)

A Circle has a Point. (O)

-> Circle은 Point를 포함함

 

4) 단일 상속(single inheritance)

- 둘 이상의 클래스로부터 상속받을 수 없음

- C++에서는 여러 조상 클래스로부터 상속받는 것이 가능한 다중상속(multiple inheritance)을 허용하지만 자바에서는 오직 단일 상속만을 허용

- 클래스 간의 관계가 보다 명확해지고 코드를 더욱 신뢰할 수 있게 만들어 줌

 

5) Object 클래스

- 모든 클래스 상속계층도의 최상위에 있는 조상클래스

- 자바의 모든 클래스들은 Object에 정의된 멤버들을 사용할 수 있음

ex) toString(), equals() 등

 

 

 

2. 오버라이딩(Overriding)

1) 오버라이딩이란?

- 조상 클래스로부터 상속받은 메서드의 내용을 변경하는 것

- 상속받은 메서드를 그대로 사용하기도 하지만, 용도에 맞게 변경해야 하는 경우 사용

 

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

class Point3D extends Point {
    int x;
    
    String getLocation() {
    	return "x: " + x + ", y: " + y + ", z: " + z;
    }
}

 

2) 오버라이딩의 조건

 

자손 클래스에서 오버라이딩하는 메서드는 조상 클래스의 메서드와 

1. 이름이 같아야 함
2. 매개변수가 같아야 함
3. 반환타입이 같아야 함

 

※ 접근 제어자(access modifier)와 예외(exception)는 제한된 조건 하에서만 다르게 변경할 수 있음

 

1. 접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없음

    public       protected       (default)       private

<- 접근범위 넓음                         접근범위 좁음 ->

2. 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없음
3. 인스턴스메서드를 static메서드로 또는 그 반대로 변경할 수 없음

 

3) 오버로딩 vs 오버라이딩

 

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

 

4) super

- 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수

- 상속받은 멤버와 자신의 멤버의 이름이 같을 때 super를 붙여서 구별함

- this와 마찬가지로 super 역시 static메서드에서는 사용할 수 없고 인스턴스메서드에서만 사용할 수 있음

 

class Parent {
    int x = 10;
}

class Child extends Parent {
    int x = 20;
    System.out.println(x);		// 20
    System.out.println(this.x);		// 20
    System.out.println(super.x);	// 10 (조상 클래스인 Parent의 x가 출력)
}    

 

 

5) super()

- 조상 클래스의 생성자

- 자손 클래스의 인스턴스 생성 시 조상 클래스의 초기화 작업이 수행되어야 함

- 자손 클래스의 생성자에서 조상 클래스의 생성자가 호출되어야 함

- 조상 클래스의 생성자 호출은 최고 조상인 Object 클래스의 생성자에 도달할 때까지 거슬러 올라감

 

this()  같은 클래스의 다른 생성자를 호출
super()  조상 클래스의 생성자를 호출

 

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

 

class Point {
    int x,y;
    
    Point(int x, int y) {
    	// 컴파일러가 super();를 자동으로 삽입
        // 조상 클래스인 Object의 생성자 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) {
    	// 조상 클래스인 Point의 생성자 Point(int x, int y)를 호출
        // 조상 클래스의 멤버 변수인 x,y를 초기화 함
    	super(x, y);
        this.z = z;
    }
    
     String getLocation() {		// 오버라이딩
    	return "x: " + x + ", y: " + y + ", z: " + z;
     }
}    

 

 

 

 

 

참고 - Java의 정석 3rd Edition (저자 : 남궁성, 출판 : 도우출판)