상속과 포함관계

정순동·2023년 12월 6일
0

자바기초

목록 보기
28/89

상속

상속이란? 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다. 상속을 통해서 클래스를 작성하면 보다 적은 양의 코드로 새로운 클래스를 작성할 수 있고 코드를 공통적으로 관리할 수 있기 때문에 코드의 추가 및 변경이 매우 용이하다.

상속을 구현하는 방법

새로 작성하고자 하는 클래스의 이름 뒤에 상속받고자 하는 클래스의 이름을 extends '클래스 이름' 으로 작성하면 된다.

	class Parent {}
    class Child extends Parent {}

이 두 클래스는 상속 관계에 있다고 하며, 상속해 주는 클래스를 '조상(부모) 클래스'라 하며 상속 받는 클래스를 '자손(자식) 클래스'라고 한다.

자손 클래스는 조상 클래스의 모든 멤버를 상속받기에, Child클래스는 Parent클래스의 멤버들을 포함한다고 할 수 있다. 만약 Parent클래스에 age라는 변수를 멤버 변수로 추가하면, Child클래스에서도 자동적으로 age라는 멤버변수가 추가된 것과 같은 효과를 얻는다.

	class Parent {
    	int age;
    }
    
    class Child extends Parnet {
    	void yourAge() {
        	System.out.println(age);
        }
    }

Child 클래스의 인스턴스를 만들었을 때 age를 생성하지 않고도 yourAge()라는 메서드를 사용할 수 있고, 반대로 Parent인스턴스를 만들었을 때 yourAge()메서드는 사용할 수 없는것을 알 수 있다.

자손 클래스는 조상 클래스의 모든 멤버를 상속 받으므로 항상 조상 클래스보다 같거나 많은 멤버를 갖는다. 또한 상속 받는다는 것은 조상 클래스를 확장(extend)한다는 의미로 해석할 수도 있다.

상속의 특징

  • 자손 클래스는 조상 클래스의 모든 멤버를 상속받는다.(단, 생성자와 초기화 블럭은 상속되지 않는다.)
  • 자손 클래스의 멤버 개수는 조상 클래스보다 항상 같거나 많다.

단일 상속(single inheritance)

자바에서는 둘 이상의 클래스로부터 상속을 받을 수는 없다. C언어등에서는 이렇게 둘 이상의 클래스로부터 상속을 받는것을 다중 상속이라고 표현하지만 이 다중 상속에는 클래스 간의 관계가 매우 복잡해질 수 있고, 다중 상속 받는 클래스 내부의 멤버간의 이름이 겹치는 등의 오류를 내기 쉽다. 이는 간단한 문제가 아니기에 자바에서는 다중 상속의 여러 이점들을 포기하고 단일 상속만을 허용한다.

오버라이딩(overriding)

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

	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를 상속받는 3차원 좌표계의 x,y,z값과 이를 출력해주는 getLocation()이라는 메서드를 가지고있다. 이 경우에서 Point를 상속받았을 때 똑같은 이름의 getLocation()을 사용하기 위해, 그리고 Point3D에 맞는 메서드를 구현하기 위해 getLocation()메서드를 오버라이딩 한 것이다.

오버라이딩의 조건

오버라이딩은 메서드의 내용만을 새로 작성하는 것이므로 메서드의 선언부(메서드 이름, 매개변수, 반환타입)는 조상의 것과 완전히 일치해야 한다. 다만 접근 제어자와 예외(exception)는 제한된 조건 하에서만 다르게 변경 가능하다.

  1. 접근 제어자는 조상 클래스의 메서드보다 좁은 범위로 변경할 수 없다.
    범위 public > protected > (default) > private 이다.
  2. 조상 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.
    	class Parent {
        	void method01() throws Exception1, Exception2 {
            	...
            }
        }
        class Child extends parent {
        	void method01() throws Exception1 {
            	...
            }
        }
    따라서 위코드는 올바르게 오버라이딩 되었다.

오버라이딩의 조건
1. 선언부가 조상 클래스의 메서드와 일치해야 한다.
2. 접근 제어자를 조상 클래스의 메서드보다 좁은 범위로 설정할 수 없다.
3. 예외는 조상 클래스의 메서드보다 많이 선언할 수 없다.

Object클래스(기초)

object클래스란? 모든 클래스의 상속계층도의 최상위에 있는 조상 클래스이다. 다른 클래스로부터 상속 받지 않는 모든 클래스들은 자동적으로 Object클래스로부터 상속받게 함으로써 이것을 가능하게 한다.
만일 다음과 같이 다른 클래스로부터 상속을 받지 않는 Tv클래스를 정의하였다고 하자.

	class Tv {
    	...
    }

위의 코드를 컴파일 하면 컴파일러는 자동으로 extends Object를 추가하여 컴파일한다. 만약 Tv 클래스가 Power클래스를 상속받았다고 치자. 그럼 Power클래스에 extends Object를 추가하여 결국에는 Object 클래스가 최상위 클래스가 된다.
Object 클래스는 Object클래스(심화)에서 자세히 다룰 예정이다.

상속 이외에도 클래스를 재사용하는 방법이 또 있다. 그 방법은 클래스 간에 '포함(composite)'관계를 맺어 주는 것이다.

포함관계

포함관계란? 한 클래스의 멤버변수로 다른 클래스 타입의 참조변수를 선언하는 것을 뜻한다.
원(Circle)을 표현하기 위한 Circle클래스와 좌표상의 한 점을 다루기 위한 Point클래스를 다음과 같이 작성되어 있다고 가정한다.

	class Circle {
    	int x;	// 원점의 x좌표
        int y;	// 원점의 y좌표
        int r;  // 원의 반지름
    }

위는 원을 나타대는 클래스, 아래는 좌표만을 나타내는 클래스이다.

	class Point {
    	int x;	// x좌표
        int y;  // y좌표
    }

이 둘을 포함관계로 만드려면 Circle클래스에서 Point클래스의 인스턴스를 만들어 포함시키면 된다.

	class Circle{
    	Point point = new Point();
        int r;
    }

이렇게 사용하면 보다 간결하고 Point클래스를 다른 클래스에서도 적용할 수 있어 매우 좋다.

클래스 간의 관계 결정하기

자, 그럼 상속으로 관계를 결정할 것이냐 아니면 포함관계로 관계를 결정할 것이냐 하는 문제가 남았다.
이럴 때는 '~은 ~이다(is-a)'와 '~은 ~을 가지고 있다(has-a)'를 넣어서 문장을 만들어 보면 클래스 간의 관계가 보다 명확해 진다.

원(Circle)은 점(Point)이다. - Circle is a Point.
원(Circle)은 점(Point)를 가지고 있다. - Circle has a Point.

아래의 문장이 더욱 옳다는 것을 알 수 있다. 따라서 이런 경우에는 상속관계보다는 포함관계로 만들어 주는것이 좋다. 반대의 경우에는 상속관계를 사용해 주면 되겠다.

0개의 댓글