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);
}
}
'Backend > 객체 지향 프로그래밍' 카테고리의 다른 글
[Java] 상속과 다형성 (Polymorphism) (0) | 2022.04.19 |
---|---|
[Java] final 클래스 final 메소드 (0) | 2022.04.18 |
[Java] Annotation (메타데이터) (0) | 2022.04.16 |
[Java] 객체의 무결성 보호 (Getter, Setter 메소드) (0) | 2022.04.15 |
[Java] 접근 제한자 (Access Modifier) (0) | 2022.04.14 |