[자바] 상속

Gammi·2022년 10월 20일
0

JAVA

목록 보기
15/35
post-thumbnail

👩‍👧 상속(inheritance)


  • is-a 관계가 성립하는 객체간의 관계

  • 슈퍼클래스의 모든 멤버를 서브클래스에서 물려받아 선언 없이 사용

    • 슈퍼클래스 = 부모클래스 = 상위클래스 = 조상클래스

    • 서브클래스 = 자식클래스 = 하위클래스 = 자손클래스


  • private 접근제한자가 지정된 멤버는 상속 대상에서 제외

  • 생성자는 상속 대상에서 제외

    -> 생성자의 이름은 자신의 클래스, 상속받은 생성자는 부모 클래스 이름이므로 규칙에 위반


  • 자바는 단일 상속만 지원

    -> 두 개 이상의 슈퍼클래스를 지정할 수 없음


  • 별도로 상속 대상을 지정하지 않을 경우 java.lang.Object 클래스 자동 상속

    -> java.lang.Object : 자바 최상위 클래스


< 상속 기본 문법 >

calss 서브클래스명 extends 슈퍼클래스명 {
}


public static void main(String[] args) {
  Child c = new Child(); // 인스턴스 생성
  c.num = 5; // 부모클래스로부터 상속받은 num 변수 초기화
  c.ParentPrn(); // 상속받아서 사용 가능
  c.showNum(); // 5 출력됨
}

class Parent{ // 부모 클래스 생성
  int num; // 부모 클래스 멤버 변수 선언
  public void ParentPrn() {
    System.out.println("슈퍼클래스의 ParentPrn()")
  }
}

class Child extends Parent { // 부모 클래스를 상속받는 자식 클래스 생성
  public void ChildPrn() {
    System.out.println("서브클래스의 ChildPrn()")
  }
  public void showNum() {
    System.out.println("부모클래스로부터 상속받은 num : " + num)
    // 부모클래스로부터 num을 상속받았기 때문에 선언하지 않고 그대로 변수 사용 가능
  }
}





👍 상속의 장점


  • 코드 재사용성 증가

  • 코드 유지보수성 용이해짐





✔ has-a 관계 vs is-a 관계


  • has-a 관계(포함)와 is-a 관계(상속)의 차이





✔ has-a 관계


  • A has a B = A가 B를 포함한다

  • 가장 일반적인 객체간의 관계

  • 특정 클래스 내에서 다른 클래스의 인스턴스를 생성하여 해당 인스턴스를 다루는 관계

    ex) 자동차 - 엔진, 스마트폰 - 카메라


class Engine {
  int cc = 3000; // 배기량
}
class Car {
  String modelName = "그랜져";
  Engine engine = new Engine();
  // 인스턴스 생성을 통해 접근 가능
  public void showInfo() {
    System.out.println(modealName);
    // 자신의 멤버변수이므로 변수명으로 바로 접근 가능
    System.out.println(engine.cc);
    // 참조변수를 통해 접근 가능
  }
}



✔ is-a 관계


  • A is a B = A는 B이다

  • 특정 클래스가 다른 클래스를 상속받아 해당 클래스의 멤버를 선언없이 다루는 관계

    ex) 자동차 - 소방차, 핸드폰 - 스마트폰


class FireEngine extends Car {
// 위의 Car 클래스를 상속받는 소방차 클래스
  int supplyLimit = 10000; // 소방차 클래스의 멤버변수
  
  public void showFireEngineInfo() {
    System.out.println(supplyLimit);
    // 본인의 멤버변수기 때문에 바로 사용 가능
    System.out.println(modelName);
    // 부모 클래스의 멤버변수 접근 가능
    System.out.println(engine.cc);
    // 부모와 포함관계인 Engine 객체에도 접근 가능
  
  }
}





✔ 상속에서의 생성자


  • 생성자: 클래스명과 이름이 같고 리턴타입이 없는 메서드의 일종

  • 생성자는 상속X

    -> 상속받을 경우 자신의 클래스명과 생성자명이 다르기 때문에 생성자 정의 규칙 위반

  • 서브 클래스 인스턴스 생성 전 슈퍼클래스 인스턴스 먼저 생성

    -> 서브클래스 생성자 호출 시 슈퍼클래스 생성자 먼저 호출하여 슈퍼클래스 인스턴스 생성 후 서브클래스 인스턴스 생성되기 때문!


< Manager 인스턴스를 생성하는 과정 >

슈퍼클래스의 인스턴스가 생성된 후 서브클래스의 인스턴스가 생성됨

  1. new Manager() 코드에 의해 "Manager() 생성자"로 이동

  2. "Manager() 생성자"에 의해 슈퍼클래스 "Employee()" 호출

    -> "Manager() 생성자" 내에 자동으로 만들어지는 super() 때문

  3. "Employee() 생성자"에서 "Object()" 호출

    -> "Employee() 생성자" 내에 자동으로 만들어지는 super() 때문

  4. Object 인스턴스 생성, "Object() 생성자" 내 코드 실행됨

  5. Employee 인스턴스 생성, "Employee() 생성자" 내 코드 실행

  6. Manager 인스턴스 생성, "Manager() 생성자" 내 코드 실행


⭐ 입력

public static void main(String[] args) {
  Manager m = new Manager("홍길동", 3000, "개발팀");
}

class Employee {
  String name;
  int salary;
  
  public Employee() {
  // 기본 생성자 정의
    super();
    System.out.println("Employee() 생성자 호출됨");
  }
}

class Manager extends Employee {
  String depart;
  
  public Manager() {
  // 기본 생성자 정의
    super();
    System.out.println("Manager() 생성자 호출됨");
  }
  
  public Manager(String name, int salary, String depart) {
  // 생성자 오버로딩
    System.out.println("Manager(String, int, int) 생성자 호출됨");
    this.name = name;
    this.salary = salary;
    this.depart = depart;
    // 부모클래스를 상속받아서 employee 클래스의 멤버변수 사용 가능
  }
}

📌 출력

Employee() 생성자 호출됨
Manager(String, int, int) 생성자 호출됨





✔ 접근제한자


접근제한자 : 멤버에 대한 접근 범위를 제한하는 키워드

public > protected > default > private

  • public : 모든 패키지의 모든 클래스에서 접근 가능
  • protected : 같은 패키지거나 다른 패키지의 서브클래스에서 접근 가능
  • default : 같은 패키지에서만 접근 가능
  • private : 자신의 클래스에서만 접근 가능

⭐ access 패키지의 Parent 클래스

package access;
public class Parent {
  public int publicVar;
  protected int protectedVar;
  int defaultVar; // default 타입은 생략 가능!
  private int privateVar;
  
  public void useMember() {
    this.publicVar = 10;
    this.protectedVar = 20;
    this.defaultVar = 30;
    this.privateVar = 40;
  }
}

  • 자신의 클래스 내의 멤버에 접근하는 것이기 때문에 제약 없이 사용 가능!


⭐ access 패키지의 Same 클래스

package access;
public class Same {
  public void useMember() {
    Parent p = new Parent();
    // 같은 패키지 내의 다른 클래스이기 때문에
    // 인스턴스 생성 후 참조변수를 통해 접근!
    // has-a 관계!!
    // 같은 패키지 내에서는 import 불필요함
    
    p.publicVar = 10;
    p.protectedVar = 20;
    p.defaultVar = 30;
    // 세 개만 접근 가능
  }
}

  • 패키지는 같지만 클래스가 다르기 때문에 private로 선언한 변수에는 접근 불가능


⭐ other 패키지의 Parent 클래스를 상속 받는 Child 클래스

package other;
import access.Parent;
// 패키지가 다르기 때문에 import 필요!

public class Child extends Child {
// Paren 클래스 상속
// 상속은 인스턴스 생성 필요없음
// 참조변수로 접근하는 게 아니니까!
  public void useMember() {
    this.publicVar = 10;
    this.protectedVar = 20;
    // 두 개만 접근 가능
    
    Parent p = new Parent();
    // 인스턴스 생성 
    p.publicVar = 10;
    // 하나만 접근 가능
  }
}

  • 상속을 받게 되면 is-a 관계이기 때문에 publicprotected로 선언한 변수에 접근 가능

  • 하지만 참조변수를 통해 접근하게 되면 상속이 아닌 has-a 관계의 포함관계이기 때문에 protected는 접근이 불가능해지고 public만 접근 가능!



⭐ other 패키지의 Parent 클래스를 상속 받지 않는 Not 클래스

package other;
import access.Parent;
// 다른 패키지라서 import 필요!

pulbic class Not {
  public void useMember() {
    Parent p = new Parent();
    p.publicVar = 10;
    // 하나만 접근 가능
  }
}

  • 참조변수를 통해 접근했기 때문에 위와 같은 이유로 public만 접근 가능!
profile
개발자가 되었어요⭐️

0개의 댓글