성장일기

내가 보려고 정리하는 공부기록

언어/자바

[JAVA] 클래스 상속

와나나나 2024. 6. 13. 23:57
728x90

자바에서 구현되어있는 라이브러리를 보면 extends 라는 글자와 함께 클래스가 마치 기차처럼 줄줄이 연결되어있는 모습을 볼 수 있다. 이것은 상속을 할 때 쓰는 명령어이다! 그렇다면 상속은 뭐고, 왜 상속을 하는걸까 ?

 

 ✅ 상속 ? 왜 하는 건데 ?

우선 상속이란, 객체지향 프로그래밍에서 부모 클래스의 멤버 (필드, 메소드) 를 자식 클래스에게 물려주는 것을 의미한다. 여기서 부모클래스를 슈퍼클래스, 자식클래스를 서브클래스라고 부르기도 한다. 

 

상속을 하는 이유는 코드를 재사용 하기 위해서이다. 잘 개발된 클래스를 상속하여, 이미 구현되어있는 기능을 가져와 쓸 수 있어 효율적으로 개발시간을 단축시킬 수도 있다.

 

상속은 아래 코드처럼 extends 를 사용해주면 된다.

 

// 부모 클래스
public class Animal {
  ...
}

// 자식 클래스
public class Dog extends Animal {
  ...
}

 

✅ 상속의 특징

상속은 다음과 같은 특징을 가진다.

 

1. 여러개의 부모클래스 상속 불가

말 그대로 여러 개의 부모클래스를 상속할 수 없다. 지원하지 않는 이유는 바로 다이아몬드 문제 때문인데, 다이아몬드 문제란 아래와 같은 상황일 때를 의미한다.

child가 father과 mother 클래스를 모두 상속한다고 가정하자. 이때 이 두 클래스에 같은 메소드가 있다면 ? 어떤 메소드를 사용해야할지 혼돈이 올 것이다. 이러한 이유로 다중상속을 지원하지 않는다.

 

2. 부모클래스에서 private 접근 제한을 갖는 필드와 메소드는 상속 불가

private 접근제한은 해당 클래스에서만 접근할 수 있게 하는 것이다. 따라서 자식 클래스에서는 접근할 수 없게 된다.

 

 

 

✅ 자식객체 생성

// 부모 클래스
public class Animal {
  ...
}

// 자식 클래스
public class Dog extends Animal {
  ...
}

 

이렇게 상속관계를 맺고

Dog dog = new Dog();

 

위와 같은 코드를 작성했다고 하자. 겉보기엔 자식클래스만 생성한 것처럼 보이지만, 부모객체가 먼저 생성된다! 나는 부모 생성자를 쓴적이 없는데..? 어째서일까 ?

 

우리가 자식 생성자를 만들지 않으면 아래와 같이 기본생성자가 만들어진다.

public Dog() {
	super();
}

 

super() 에 의해 부모 생성자가 불려서 생성되는 것이다. 

super()는 부모의 기본 생성자를 호출하는 명령어이다. 만약 직접 자식 생성자를 선언할 것이라면,

// 부모 클래스
public class Animal {
  private String name;
  private String kinds;
  
  public Animal() {
  }

  public Animal(String name, String kinds) {
      this.name = name;
      this.kinds = kinds;
  }
}

// 자식 클래스
public class Dog extends Animal {
  private int weight;

  public Dog() {
    // super() 생략 시 자동으로 생성한다.
  }

  public Dog(String name, String kinds, int weight) {
    super(name, kinds);

    this.weight = weight;
  }
}

 

이런식으로 super() 안에 매개변수를 넣어준다. 이때 매개변수의 타입과 일치하는 부모 생성자가 없으면 에러가 발생한다.

추가로 super()은 메소드 내부에서 제일 위에 넣어주어야 한다. 안그러면 에러뜸

 

 

✅ 메소드 재정의

엥 나는 부모 클래스의 메소드를 그대로 가져오기 싫은디 ? 라면 재정의해주면 된다. 이때 Override라는 애노테이션을 달아준다. 물론 생략해도 상관은 없다.

 

오버라이딩

오버라이딩은 부모클래스의 메소드를 자식 클래스에서 다시 재정의해 사용하는 것을 의미한다. 이때 두가지를 유의하자.

  • 부모의 메소드와 선언부가 동일해야한다. (리턴타입, 메소드명, 매개변수목록 동일)
  • 부모의 메소드가 private 접근제한을 가지면 오버라이딩 할 수 없다.
  • 부모 메소드보다 접근 제한을 더 강하게 정의할 수 없다.
// 부모 클래스
public class Animal {
  private String name;
  private String kinds;
  
  public Animal() {
  }

  public Animal(String name, String kinds) {
      this.name = name;
      this.kinds = kinds;
  }

  public String bark() {
      return "짖는다.";
  }
}

// 자식 클래스
public class Dog extends Animal {
  private int weight;

  public Dog() {
  }

  public Dog(String name, String kinds, int weight) {
    super(name, kinds);

    this.weight = weight;
  }

  @Override
  public String bark() {
      return "멍멍";
  }
}

 

자식 객체에서 오버라이딩 된 메소드를 호출하면, 오버라이딩 된 자식 메소드가 호출된다. 즉, 부모 객체의 메소드가 오버라이딩 된 메소드에 의해 가려지는 것이다. (삭제되는 게 아니다)