상속

상속

Inheritance : 새로운 A객체가 기존에 있던 B객체가 갖고있는 변수, 메소드를 물려 받고, 새로운 변수나 메소드를 생성하거나 변경하는 것

객체 = 필드(변수)+메소드

 

우리가 기존 Calculator 예제에서 sum객체와 avg객체를 만들었잖아. 이걸 내가 아닌 다른 사람이 만들었다고 치고,

우리는 여기에 substract객체를 새로 추가하고 싶어. 그런데 기존에 복붙한 Calculator의 소스가 없거나, 있다 하더라도 다른 곳에서는 불필요한 기능일 수가 있어. 그럼 다른 사용자는 substract가 무엇인지 파악해야하는 번거로움이 생겨

등등의 불편함을 극복! 한 것이 상속

→ 기존의 객체를 그대로 유지함과 동시에, 또 다른 기능을 추가하는 방법 = 상속

기존의 객체 = 부모 객체 (기능을 물려줌) : 상위 클래스(super class)

새로운 객체 = 자식 객체 (그 기능을 물려받음) : 하위 클래스 (sub class), 기초 클래스(base~), 유도 클래스(derived~)

derive 파생

 


기존에 세팅했던 setOprands, sum, avg를 새로운 클래스에서 사용할 수 있는 이유 = extends 클래스이름 덕분이얌

새로운 클래스가 기존 클래스의 기능을 사용할 수 있게 확장했기 때문

클래스 다이어그램(클래스와 클래스의 관계를 그림으로 표현)

SC는 C를 상속한다. 확장한다. extend한다.

 

더보기

💡 까먹을까봐 계속 반복하는 정의들

c1 : SubstractableCalculator class담은 인스턴스

c1.setOprnads(), c1.sum(), c1.avg(), c1.substract() 라는 메소드 호출


부모객체 아래에는 또 다른 자식객체가 올 수 있어

한 패키지 안에 같은 이름의 클래스가 두개 이상 존재하지 않아

그래서 두번째 예제 클래스에 calss Calculator가 없어도 extends Calculator(부모객체를 상속하는 것이) 가능

package org.oepntutorials.javatutorials.inheritance;

class MultiplicationableCalculator() extends Calculator {
   public void multiplication() {
      System.out.println(this.left * this.right);
   }
}

public class Ex02_Calculator {
   public static void main(String[] args) {
      MultiplicationableCalculator c1 = new MultiplicationableCalculator();
      c1.setOprands(10, 20);
      c1.sum(); //30
      c1.avg(); //15
      c1.multiplication(); //200
   }
}

L3을 통해 Calculator클래스의 기능들을 그대로 상속하면서 multiplication메소드를 추가로 정의할 수 있게 됨

 

더보기

💡 그럼 substract 메소드도 사용하고 싶을면?

package org.oepntutorials.javatutorials.inheritance;

class MultiplicationableCalculator() extends SubstractableCalculator {
   public void multiplication() {
      System.out.println(this.left * this.right);
   }
}

public class Ex02_Calculator {
   public static void main(String[] args) {
      MultiplicationableCalculator c1 = new MultiplicationableCalculator();
      c1.setOprands(10, 20);
      c1.sum();
      c1.avg();
      c1.multiplication();
      c1.substract(); // -10
   }
}

부모객체를 substractableCalculator로 하게되면 substract메소드도 사용할 수 있어!

그런데 setOprands부터 avg는 어떻게 사용가능할까?

SubstractableCalculator 클래스의 부모객체가 위 기능들이 있는 Calculator 클래스이니까 사용 가능하단거지 무야호

 

부모객체를 상속하는 자식객체를 상속하는 자식객체

class DivisionableCalculator extends MultiplicationableCalculator {
   public void division() {
      System.out.println(this.left / this.right);
   }
}

public class Ex03_Calculator {
   public static void main(String[] args) {
      DivisionableCalculator c1 = new DivisionableCalculator();
      c1.setOprands(10, 20);
      c1.sum();
      c1.avg();
      c1.multiplicaion();
      c1.division();
   }
}

상속의 장점

  • 코드의 중복 제거
  • 재활용성 ↑
  • 가독성 ↑
  • 유지보수의 편의성 ↑

상속과 생성자

class 아래에 main메소드가 자기 자신을 인스턴스화할 수 있어!

public class ConstructorDemo {
   public static void main(String[] args) {
      ConstructorDemo c = new ConstructorDemo();
   }
}

이 경우에 기본생성자를 선언하지 않았는데도 ConstructorDemo라는 생성자(L3.우항)를 new(생성)할 수 있는 이유는 Java가 자동으로 기본생성자를 만들어 주기 때문이야 (public ConstructorDemo {} - 여기에는 아무 내용X)

 

public class ConstructorDemo {
   public ConstructorDemo(int param1) {}
   public static void main(String[] args) {
      ConstructorDemo c = new ConstructorDemo();
   }
} // Err

ConstructorDemo 클래스 안에 ConstructorDemo 생성자를 선언했는데, 매개변수(파라미터)가 있음 = 기본 생성자 아님

→ main메소드 안에서 CD클래스를 인스턴스화하면 Err

why? class를 생성했을 때 생성자를 선언하지 않으면, Java는 기본생성자를 자동으로 만들어줌

기본 생성자는 class의 이름과 같고, 매개변수는 없는 메소드

기본 생성자가 아닌 생성자(매개변수가 있는 생성자)를 정의했을 때, Java는 기본 생성자가 아니더라도 생성자가 하나라도 있으면 자동으로 기본 생성자를 만들어주지 않아.

main메소드 안에서는 ConstructorDemo 생성자를 호출했는데, L2에서 CD 생성자는 param1이라는 인자를 갖고 있고, L4에서 호출한 CD생성자는 인자를 갖고있지 않아서 Err가 발생 (Java가 인자가 없는 CD 기본 생성자를 만들어주지 X)

 

그렇다면 Err를 해결하기 위해서! 

인자가 없는 기본생성자를 만들어주면돼!! → L2

public class ConstructorDemo {
   public ConstructorDemo() {} // 인자가 없는 기본 생성자를 만들어주었기 때문에 오류 해결!
   public ConstructorDemo(int param1) {}
   public static void main(String[] args) {
      ConstructorDemo c = new ConstructorDemo();
   }
}

 

더보기

💡 "초기화와 생성자" 글에서 public Calculator() n{} 가 기본생성자가 아니고, 파라미터가 있는데 왜 오류가 안났냐고?

Calculator생성자를 main메소드에서 선언할 때, 10과 20을 인자값으로 주었기 때문이지!

인자값을 넣지 않고 선언했다면 오류가 발생했을거야

또, 상속의 개념이 이 예제에는 없어서 매개변수가 없는 기본생성자가 없고, 매개변수가 있는 생성자만 있어도 오류가 안 났던거야


super

식클래스가 상속받을 때, 부모클래스의 기본생성자를 자동으로 호출해야 함.

부모클래스가 매개변수가 있는 생성자를 선언하면 자바는 기본생성자를 자동 생성 X

→ 자식생성자는 기본생성자를 호출X → Err

 

또, 자식클래스와 부모클래스의 로직이 중복돼 = 유지보수 힘듦, 코드 많아짐, 재활용성 ↓ 등의 문제 발생

 

해결방법?

1️⃣ 부모클래스에 매개변수가 없는 기본생성자를 추가로 만들면 해결! 빠밤

class Calculator2 {
   int left, right;

   public Calculator2() {} // Calculator2의 기본생성자 (class이름과 같고, 파라미터 없음)
   
   public Calculator2(int left, int right) {
      this.left = left;
      this.right = rigth;
   }
}

2️⃣ super( ) = 부모클래스의 생성자임을 의미

this. 가 자기 자신을 의미하는 것처럼,,

하위클래스의 기존 로직 대신 super(left, right); 를 사용함으로써 코드 중복을 없앴고, 유지보수의 간편함, 재활용성 ↑등의 장점이 생김!

super( )는 상위클래스를 의미하기 때문에 바로 Calculator2 클래스로 갈거야, 그 다음 매개변수가 있는 하위클래스니까 기본생성자가 아닌 매개변수가 있는 상위클래스의 생성자로 감

 

super( ); 를 사용 시 주의사항

하위 클래스를 초기화해주는 코드를 super보다 먼저 작성하면 Err

반드시 super 다음에 하위클래스의 초기화 코드 작성하기

하위 클래스가 만들어진다 = 하위 클래스가 인스턴스화 된다 = 상위 클래스가 이미 인스턴스화 됐음

= 상위 클래스의 초기화가 이루어진 다음에 하위 클래스의 초기화가 이루어질 수 있다

 

'하다보면 되겠지 머.,. > 생활코딩_JAVA' 카테고리의 다른 글

오버로딩  (0) 2021.10.23
오버라이딩  (0) 2021.10.23
초기화와 생성자  (0) 2021.10.22
유효범위 : this  (0) 2021.10.22
유효범위  (0) 2021.10.13