Java

[Java] 상속과 구성

jny0 2023. 2. 23. 14:32

객체지향은 중복코드를 없애기 위해서 존재한다.

객체지향적인 구조를 위해서 일부러 중복코드를 허용하는 경우도 있다.

다형성  = 같은 타입이지만 실행결과가 다양한 객체를 이용할 수 있는 성질. 하나의 타입에 여러 객체를 대입하여 만든다.

 

상속(Inheritance)

부모클래스를 상속하는 자식클래스는 부모클래스의 기능을 그대로 물려받아 중복코드를 제거할 수 있다.

이후 유지보수가 편해지며 다형성을 구현할 수 있는 장점이 있다.

자식클래스에 메서드를 추가하여 부모클래스의 기능을 확장할 수 있다. extends 키워드 사용

class 오리 {
    void 날다();
    void 수영하다();
}
class 흰오리 extends 오리{
    void 걷다();
}

 

IS-A 관계

흰오리는 오리이다 처럼 말할 수 있는 관계를 IS-A 관계라고 한다.

이렇게 IS-A 관계(상속관계)에 있을 때 자식 클래스의 객체는 부모 클래스의 자료형인 것처럼 사용할 수 있다.

오리 a오리 = new 흰오리();

 

메서드 오버라이딩

부모클래스의 메서드를 자식클래스가 동일한 형태로 다시 구현하는 행위 (덮어쓰기)

고무오리 class에 날다 메서드를 다시 구현

class 오리 {
    void 날다() { System.out.println("오리가 날개로 날아갑니다.");  }
    void 수영하다();
}

class 흰오리 extends 오리 {
    void 걷다();
}

class 고무오리 extends 오리 {
    void 날다() {  System.out.println("저는 못 날아요.");   }    // 메서드 오버라이딩
}

 

메서드 오버로딩

입력항목이 다른 경우 동일한 이름의 메서드를 만들 수 있다.

class 오리 {
    void 날다() { System.out.println("오리가 날개로 날아갑니다.");  }
    void 수영하다();
}

class 흰오리 extends 오리 {
    void 걷다();
}

class 고무오리 extends 오리 {
    void 날다() {  System.out.println("저는 못 날아요.");   }
    void 날다(int hp) {  System.out.println("hp가 있으면 고무오리도 날 수 있어요.");   } 
    // 메서드 오버로딩. 동일한 날다 메서드지만 int 자료형이 입력항목으로 추가됨. 

}

자바는 다중 상속을 지원하지 않는다. 따라서 고무오리 클래스가 오리흰오리를 같이 상속하는 것은 불가능하다.

 

상속을 통한 캐스팅(강제형변환) 허용

- 부모 타입에는 모든 자식 객체가 대입될 수 있다.

- 부모 타입으로 자동형변환된 자식객체는 강제형변환을 통해 다시 자식 타입으로 바꿀 수 있다.

- 강제형변환은 자동형변환을 거친 경우에만 사용할 수 있다! 

부모 부 = new 부모(); //  가능
부모 부 = new 자식(); //  가능
자식 자 = new 부모(); //  불가능


Animal animal = new Animal();
Dog dog = new Dog();
animal = new Dog() // 자동형변환
dog = (Dog)animal // 강제형변환

 

상속의 단점

   - 상속은 단일 패키지에서 사용해야만 안전하다.

   - 하위 클래스는 상위 클래스에 많이 의존하게 된다.

   - 상위 클래스의 코드가 수정되면 하위 클래스의 코드도 수정되어야 하는 경우가 많다. (재정의 메소드)

   - 확장이라는 목표를 두고 상속을 사용하면 괜찮으나, 해당 설계가 아닌 상황에서 상속을 사용할 시 문제를 발생할 수 있다.

   -상속은 캡슐화를 위반한다(하위 클래스가 상위 클래스에 구체적인 구현 내용을 의존하기 있기 때문이다)

 

 

 

구성(Composition)

상속의 취약점을 피하고 싶다면 구성을 사용한다.

구성은 상속과 다르게 Has-A 관계를 가진다.

구성은 하위 클래스가 상위 클래스를 상속받는 것이 아니라 단순히 하위 클래스가 상위 클래스를 private으로 참조받아서 사용하는 것이다. 

class 오리 {
    void 날기();
    void 수영하기();
}

class 흰오리 extends 오리{	// 이미 오리를 상속받아서 로봇오리의 기능은 사용 불가
    void 걷기();
    
    소리나기 a소리 = new 소리나기();
    void 소리나기(){
    	a소리.소리나기();		 	// 구성을 사용하여 로봇오리의 기능 사용하기
    }
}

class 로봇오리{
	void 소리나기();
}