본문으로 바로가기

1. 상속

  • 상속(Inheritance)은 부모가 자식에게 물려주는 행위
  • 자식 클래스명 뒤에 extends 키워드를 붙이고 그 뒤에 상속할 부모 클래스를 선언
  • 자바에서는 다중 상속을 지원하지 않습니다.
  • 프로그램에서의 상속은 자식이 부모를 선택합니다.
  • 부모 클래스(상위 클래스) <---> 자식 클래스(하위 클래스, 파생 클래스)
class 자식클래스 extends 부모클래스 {
    // 필드
    
    // 생성자
    
    // 메소드
}

 

장점

  • 코드의 중복을 줄여줍니다.
  • 개발 시간을 절약(효율적 개발)
  • 부모 클래스의 수정으로 모든 자식 클래스들의 수정 효과를 가져오기 때문에 유지 보수 시간을 최소화

 

예시

다음과 같이 Computer 클래스를 상속받은 MacBook 클래스는

Computer 클래스에서 구현된 on, off 메소드를 사용할 수 있습니다.

따라서 중복으로 작성할 필요도 사라지고 개발 시간도 절약됩니다.

public class Computer {
    String serialName;
    
    public void on() {
        System.out.println("ON");
    }

    public void off() {
        System.out.println("OFF");
    }
}
public class MacBook extends Computer {
    public void airPlay() {
        System.out.println("air play 활성화");
    }
}
MacBook macBook = new MacBook();
Gram gram = new Gram();

// 부모 클래스의 메소드를 사용할 수 있습니다.
macBook.on(); // ON
macBook.off(); // OFF
macBook.airPlay(); // air play 활성화

 

주의할 점

  • 상속을 해도 부모 클래스의 모든 필드와 메소드를 물려받는 것은 아닙니다.
  • private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외됩니다.
  • default 접근 제한을 갖는 필드와 메소드는 부모 클래스와 자식 클래스가 다른 패키지에 존재한다면 상속 대상에서 제외됩니다. 

 

예시

B 클래스는 A 클래스를 상속받았으나,

특정 필드와 메소드는 private 접근 제한을 가지고 있으므로 

private 접근 제한을 가지고 있는 해당 필드와 메소드는 접근이 불가능합니다. (field2, printField2())

public class A {
    public String field1 = "field1";
    private String field2 = "field2";

    public void printField1() {
        System.out.println(this.field1);
    }

    private void printField2() {
        System.out.println(this.field2);
    }
}
public class B extends A {

}
B b = new B();

String field1 = b.field1;
b.printField1();

// String field2 = b.field2; (x)
// b.printField2(); (x)

 

2. 부모 생성자

상속 시 객체 생성

  • 자식 객체를 생성하면, 부모 객체가 먼저 생성되고 자식 객체가 그다음에 생성됩니다.
  • 모든 객체는 클래스의 생성자를 호출해야만 생성됩니다. 따라서 자식 객체를 생성하려면 부모 생성자를 호출해야 합니다.
  • 반드시 자식 생성자의 첫 줄에 위치해야 합니다. (부모가 있어야 자식이 존재할 수 있습니다.)
  • 부모, 자식 클래스의 생성자를 명시적으로 선언하지 않았다면 컴파일러는 기본 생성자를 생성합니다.

 

부모 생성자 호출

  • 매개값의 타입과 일치하는 부모 생성자를 호출
public 자식클래스() {
    super( [매개값], ... ); // 부모 생성자 호출
}

 

예시

public class A {
    String fieldA1;
    String fieldA2;

    public A(String fieldA1) {
        this.fieldA1 = fieldA1;
    }

    public A(String fieldA1, String fieldA2) {
        this.fieldA1 = fieldA1;
        this.fieldA2 = fieldA2;
    }
}
public class B extends A {
    String fieldB1;

    public B(String fieldA1, String fieldB1) {
        super(fieldA1); // A(String fieldA1)
        this.fieldB1 = fieldB1;
    }

    public B(String fieldA1, String fieldA2, String fieldB1) {
        super(fieldA1, fieldA2); // A(String fieldA1, String fieldA2)
        this.fieldB1 = fieldB1;
    }
}

 

부모, 자식 필드 명이 같을 경우 접근 예시

  • 부모, 자식 필드 명이 같을 경우에 부모에 접근을 위해서는 super를 사용하면 됩니다.
public class A {
    String field1;

    public A(String field1) {
        this.field1 = field1;
    }
}
public class B extends A {
    String field1;

    public B(String field1, String field2) {
        super(field1); // 부모 생성자 호출
        this.field1 = field2;
    }

    void printField() {
        System.out.println(super.field1); // 부모 클래스 필드
        System.out.println(this.field1); // 자기 자신 클래스 필드
    }
}

 

3. 메소드 재정의 (Method Overriding)

  • 부모 클래스의 메소드 중 자식 클래스에 적합하지 않은 메소드일 경우 자식 클래스에서 수정할 수 있습니다.
  • 같은 메소드 명이지만 다른 기능을 가질 수 있습니다.
  • 오버 라이딩할 경우 부모 객체의 메소드는 숨겨집니다.
  • 오버 라이딩 = riding(타서) Over(뛰어 넘는다) = 부모 클래스를 뛰어넘는다. (쉽게 외우기)

 

재정의

  • 부모의 메소드와 동일한 시그니처(리턴 타입, 메소드 이름, 매개 변수 리스트)를 가져야 합니다.
  • 접근 제한을 부모 클래스에 정의되어 있는 것 보다 더 강하게 오버 라이딩할 수 없습니다.
  • 새로운 예외를 throws를 할 수 없습니다.
  • @Override 어노테이션 사용을 권장

 

예시

public class A {
    public String fieldA = "A Field";

    public void printField() {
        System.out.println("A클래스 필드: " + this.fieldA);
    }
}
public class B extends A {
    public String fieldB = "B Field";

    /**
     * 자식 클래스의 필드도 출력할 수 있도록 재정의(오버라이딩)
     */
    @Override
    public void printField() {
        System.out.println("A클래스 필드: " + this.fieldA);
        System.out.println("B클래스 필드: " + this.fieldB);
    }
}
A a = new A();
a.printField(); // A클래스 필드: A Field

System.out.println("-----------------");

B b = new B();
b.printField();
// A클래스 필드: A Field
//B클래스 필드: B Field

 

부모 메소드 호출

  • 자식 클래스 내부에서 오버 라이딩된 부모 클래스의 메소드를 호출해야 하는 상황이 발생한다면 명시적으로 super 키워드를 붙여서 사용합니다.
super.부모메소드();

 

예시

public class A {
    public String fieldA = "A Field";

    public void printField() {
        System.out.println("A클래스 필드: " + this.fieldA);
    }
}
public class B extends A {
    public String fieldB = "B Field";

    /**
     * 자식 클래스의 필드도 출력할 수 있도록 재정의(오버라이딩)
     */
    @Override
    public void printField() {
        super.printField(); // 부모 클래스의 메소드 실행
        System.out.println("B클래스 필드: " + this.fieldB);
    }
}