07-1. 상속
by Hi.Claire📓 혼자 공부하는 자바 (신용권, 한빛미디어)
07. 상속
07-1. 상속
상속(inheritance)
부모 클래스를 자식 클래스에게 물려주는 것
부모 클래스를 상위 클래스라고 부르고, 자식 클래스를 하위 클래스 또는 파생 클래스라고 부른다.
상속은 이미 잘 개발된 클래스를 재사용해서 새로운 클래스를 만들기 때문에 중복되는 코드를 줄여준다.
상속을 이용하면 부모 클래스의 수정으로 모든 자식 클래스들도 수정되는 효과를 가져오기 때문에 유지 보수 시간을 최소화할 수 있다.
07-1-1. 클래스 상속
자식 클래스를 선언할 때 어떤 부모 클래스를 상속받을 것인지 결정하여 extends 키워드 뒤에 기술한다.
class 자식클래스 extends 부모클래스 {...}
자바에서 상속은 다음과 같은 특징을 가지고 있다.
- 자바는 다중 상속을 허용하지 않는다. 즉, 여러 개의 부모 클래스를 상속할 수 없다.
- 부모 클래스의 private 접근 제한을 갖는 필드와 메소드는 상속 대상에서 제외된다. 그리고 부모 클래스와 자식 클래스가 다른 패키지에 존재한다면 default 접근 제한을 갖는 필드와 메소드도 상속 대상에서 제외된다.
07-1-2. 부모 생성자 호출
자식 객체를 생성하면, 부모 객체가 먼저 생성되고 그 다음에 자식 객체가 생성된다.
모든 객체는 클래스의 생성자를 호출해야만 생성된다. 부모 객체 역시 예외가 아니다.
이때 부모 생성자는 자식 생성자의 맨 첫 줄에서 호출된다.
만약, 자식 클래스에 생성자가 명시적으로 선언되어 있지 않다면 컴파일러는 다음과 같은 기본 생성자를 생성한다.
public 자식클래스() {
super();
}
이때, super()가 부모의 기본 생성자를 호출한다.
부모 클래스에도 생성자가 선언되어 있지 않다면 컴파일러에 의해 기본 생성자가 만들어져 문제없이 실행된다.
public 부모클래스() {
}
만약 부모 클래스에 기본 생성자가 없고, 매개 변수가 있는 생성자만 있다면 자식 생성자에 반드시 부모 생성자 호출을 위해 super(매개값, ...)을 명시적으로 호출해야 한다. 이때 부모 생성자인 super(매개값, ...)은 반드시 자식 생성자 맨 첫 줄에 위치해야 하며, 그렇지 않으면 컴파일 에러가 발생한다.
예시1. 부모 클래스
public class People {
public String name;
public String ssn;
public People(String name, String ssn) {
this.name = name;
this.ssn = ssn;
}
}
예시2. 자식 클래스
public class Student extends People {
public int studentNo;
public Student(String name, String ssn, String studentNo) {
super(name, ssn);
this.studentNo = studentNo;
}
}
자식 클래스의 생성자 맨 첫 줄에 있는 super(name, ssn)은 부모 클래스의 생성자인 People(String name, String ssn)을 호출한다.
예시3. 자식 객체 이용
public class StudentExample {
public static void main(String[] args) {
Student student = new Student("홍길동", "123456-1234567", 1);
System.out.println("name : " + student.name);
System.out.println("ssn : " + student.ssn);
System.out.println("studentNo : " + Student.studentNo);
}
}
name : 홍길동
ssn : 123456-1234567
studentNo : 1
07-1-3. 메소드 재정의
메소드 재정의(Overriding)
부모 클래스로부터 상속받은 메소드를 자식 클래스에서 다시 정의하는 것
메소드 재정의 방법
- 부모 메소드와 동일한 시그너처(리턴 타입, 메소드 이름, 매개 변수 목록)를 가져야 한다.
- 접근 제한을 더 강하게 재정의할 수 없다. 단, 그 반대는 가능하다.
- 새로운 예외(Exception)를 throws할 수 없다.
- @Override 어노테이션은 생략해도 좋으나, 이것을 붙여주면 해당 메소드가 정확히 재정의된 것인지 컴파일러가 확인하기 때문에 개발자의 실수를 줄여준다.
메소드가 재정의되었다면 부모 객체의 메소드는 숨겨지기 때문에, 자식 객체에서 메소드를 호출하면 재정의된 자식 메소드가 호출된다.
예시1. 부모 클래스
public class Calculator {
double areaCircle(double r) {
System.out.println("Calculator 객체의 areaCircle() 실행");
return 3.14159 * r * r;
}
}
예시2. 자식 클래스
public class Computer extends Calculator {
@Override
double areaCircle(double r) {
System.out.println("Computer 객체의 areaCircle() 실행");
return Math.PI * r * r;
}
}
예시3. 메소드 재정의 테스트
public class ComputerExample {
public static void main(String[] args) {
int r = 10;
Calculator calculator = new Calculator();
System.out.println("원면적 : " + calculator.areaCircle(r));
System.out.println();
Computer computer = new Computer();
System.out.println("원면적 : " + computer.areaCircle(r));
}
}
Calculator 객체의 areaCircle() 실행
원면적 : 314.159
Computer 객체의 areaCircle() 실행
원면적 : 3.141592653589793
이클립스의 재정의 메소드 자동 생성 기능
자식 클래스에서 [Source] - [Override/Implement Methods] 메뉴를 선택하고, 부모 클래스에서 재정의될 메소드를 선택한다.
부모 메소드 호출
자식 클래스 내부에서 재정의된 부모 클래스의 메소드를 호출할 때에는 명시적으로 super 키워드를 붙여서 부모 메소드를 호출한다.
super.부모메소드();
예시1. 부모 클래스
public class Airplane {
public void land() {
System.out.println("착륙합니다.");
}
public void fly() {
System.out.println("일반비행합니다.");
}
public void takeoff() {
System.out.println("이륙합니다.");
}
}
예시2. 자식 클래스
public class SupersonicAirplane extends Airplane {
public static final int NORMAL = 1;
public static final int SUPERSONIC = 2;
public int flyMode = NORMAL;
@Override
public void fly() {
if(flyMode == SUPERSONIC) {
System.out.println("초음속비행합니다.");
} else {
super.fly();
}
}
}
예시3. super 변수 사용 테스트
public class SupersonicAirplaneExample {
public static void main(String[] args) {
SupersonicAirplane sa = new SupersonicAirplane();
sa.takeoff();
sa.fly();
sa.flyMode = SupersonicAirplane.SUPERSONIC;
sa.fly();
sa.flyMode = SupersonicAirplane.NORMAL;
sa.fly();
sa.land();
}
}
이륙합니다.
일반비행합니다.
초음속비행합니다.
일반비행합니다.
착륙합니다.
07-1-4. final 클래스와 final 메소드
필드를 선언할 때 final이 지정되면 초기값 설정 후 더이상 값을 변경할 수 없음을 의미한다.
클래스와 메소드를 선언할 때 final 키워드가 지정되면 상속과 관련이 있다는 의미이다.
상속할 수 없는 final 클래스
클래스를 선언할 때 final 키워드를 class 앞에 붙이면 해당 클래스는 최종적인 클래스이므로 상속할 수 없는 클래스가 된다.
즉, final 클래스는 부모 클래스가 될 수 없기 때문에 자식 클래스를 만들 수 없다.
public final class 클래스 { ... }
final 클래스의 가장 대표적인 예는 자바 표준 API에서 제공하는 String 클래스이다.
public final class String { ... }
재정의할 수 없는 final 메소드
메소드를 선언할 때 final 키워드를 붙이면 이 메소드는 최종적인 메소드이므로 재정의할 수 없는 메소드가 된다.
즉, 부모 클래스를 상속해서 자식 클래스를 선언할 때 부모 클래스에 선언된 final 메소드는 자식 클래스에서 재정의할 수 없다.
public final 리턴타입 메소드(매개변수, ...) { ... }
'☕️ Java > 혼자 공부하는 자바' 카테고리의 다른 글
07-3. 추상 클래스 (0) | 2023.09.24 |
---|---|
07-2. 타입 변환과 다형성 (1) | 2023.09.23 |
06-6. 패키지와 접근 제한자 (0) | 2023.09.17 |
06-5. 인스턴스 멤버와 정적 멤버 (0) | 2023.09.13 |
06-4. 메소드 (0) | 2023.09.13 |
블로그의 정보
Claire's Study Note
Hi.Claire