상속
이미 잘 개발된 클래스를 재사용해서 새로운 클래스를 만들기 때문에 중복되는 코드를 줄여주며, 상속을 이용하면 부모 클래스의 수정으로 모든 자식 클래스들도 수정되는 효과를 가져오기 때문에 유지 보수 시간을 최소화할 수도 있음.
클래스 상속
// 기본 형식
class 자식클래스 extends 부모클래스 {
// 필드
// 생성자
// 메소드
}
예제
// 부모 클래스
package sec01.exam01;
public class People {
public String name;
public String ssn;
public People(String name, String ssn) {
this.name = name;
this.ssn = ssn;
}
}
// 자식 클래스
package sec01.exam01;
public class Student extends People {
public int studentNo;
public Student(String name, String ssn, int studentNo) {
super(name, ssn); // 부모 생성자 호출
this.studentNo = studentNo;
}
}
* super( )는 부모의 기본 생성자를 호출.
// 자식 객체 이용
package sec01.exam01;
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
메소드 재정의
메소드 재정의(overriding)은 자식 클래스에서 부모 클래스의 메소드를 다시 정의하는 것을 말하며, 주의할 점으론 부모의 메소드와 동일한 시그니처(리턴 타입, 메소드 이름, 매개 변수 목록)을 가져야하고 접근 제한을 더 강하게 재정의 할 수 없으며, 새로운 예외를 throw할 수 없다는 점이 있다.
// 부모 클래스
package sec01.exam02;
public class Calaulator {
double areaCircle(double r) {
System.out.println("Calculator 객체의 areaCircle() 실행");
return 3.14159 * r * r;
}
}
// 자식 클래스
package sec01.exam02;
public class Computer extends Calculator {
@Override // 재정의
double areaCircle(double r) {
System.out.println("Computer 객체의 areaCircle() 실행");
return Math.PI * r * r;
}
}
// 메소드 재정의 테스트
package sec01.exam02;
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)); // 재정의된 메소드 호출
}
}
부모 메소드 호출
자식 클래스에서 부모 클래스의 메소드를 재정의하게 되면, 부모 클래스의 메소드는 숨겨지고 재정의된 자식 메소드만 사용되지만, 자식 클래스 내부에서 재정의된 부모 클래스의 메소드를 호출해야 하는 상황이 발생한다면 명시적으로 super 키워드를 붙여서 부모 메소드를 호출 할 수 있음.
// super 변수
package sec01.exam03;
public class Airplane {
public void lane() {
System.out.println("착륙합니다.");
}
public void fly() {
System.out.println("일반 비행합니다.");
}
public void takeOff() {
System.out.println("이륙합니다.");
}
}
// super 변수
package sec01.exam03;
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(); // Airplane객체의 fly()메소드 호출
}
}
}
// super 변수
package sec01.exam03;
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();
}
}
// 실행 결과
// 이륙합니다.
// 일반 비행합니다.
// 초음속 비행합니다.
// 일반 비행합니다.
// 착륙합니다.
final 클래스와 메소드
final 키워드는 클래스, 필드, 메소드를 선언할 때 사용할 수 있는데, 해당 선언이 최종 상태이고 결코 수정될 수 없을을 뜻한다.
상속할 수 없는 final 클래스
클래스를 선언할 때 final 키워드를 class 앞에 붙이면 이 클래스는 최종적인 클래스이므로 상속할 수 없는 클래스가 된다. 즉, final 클래스는 부모 클래스가 될 수 없어 자식 클래스를 만들 수 없다.
// 상속할 수 없는 final 클래스
package sec01.exam04;
public final class Member{
}
// 상속할 수 없는 final 클래스
package sec01.exam04;
public class VeryImportantPerson extends Member{ // Member를 상속할 수 없음.
}
재정의할 수 없는 final 메소드
메소드를 선언할 때 final 키워드를 붙이면 이 메소드는 최종적인 메소드이므로 재정의할 수 없는 메소드가 된다. 즉, 부모 클래스를 상속해서 자식 클래스를 선언할 때 부모 클래스에 선언된 final 메소드는 자식 클래스에서 재정의할 수 없다는 것.
// 재정의할 수 없는 final 메소드
package sec01.exam05;
public class Car {
// 필드
public int speed;
// 메소드
public void speedUp(){speed +=1;}
// final 메소드
public final void stop() {
System.out.println("차를 멈춤");
speed = 0;
}
}
// 재정의할 수 없는 final 메소드
package sec01.exam05;
public class SportsCar extends Car {
@Override
public void speedUp() { speed +=10;}
@Override // 재정의할 수 없음.
public void stop() {
System.out.println("스포츠카를 멈춤");
speed = 0;
}
}
protected 접근 제한자
상속과 관련이 있는 protected는 public과 default 접근 제한의 중간쯤에 해당하는데, 같은 패키지에서는 default와 같이 접근 제한이 없지만, 다른 패키지에서는 자식 클래스만 접근을 허용하며 protected는 필드와 생성자, 메소드 선언에 사용될 수 있음.
// protected 접근 제한자
package sec01.exam06.pack1;
public class A {
protected String field;
protected A() {
}
protected void method() {
}
}
// protected 접근 제한자 태스트
package sec01.exam06.pack1;
public class B {
public void method() {
A a = new A(); // 접근 가능
a.field = "value";
a.method();
}
}
// protected 접근 제한자
package sec01.exam06.pack2;
import sec01.exam06.pack1.A;
public class D extends A {
public D() {
super(); // 접근 가능
this.field = "value";
this.method();
}
}
🔘 상속: 부모 클래스의 필드와 메소드를 자식 클래스에서 사용할 수 있도록 함.
🔘 메소드 재정의: 부모 메소드를 자식 클래스에서 다시 정의하는 것
🔘 final 클래스: final 키워드로 선언된 클래스는 부모 클래스로 사용할 수 없는 final 클래스.
🔘 final 메소드: final 키둬드로 선언된 메소드는 자식 클래스에서 재정의할 수 없는 final 메소드.
'Java' 카테고리의 다른 글
| [Java] 추상 클래스 (0) | 2025.11.14 |
|---|---|
| [Java] 타입 변환과 다형성 (0) | 2025.11.12 |
| [Java] 패키지와 접근 제한자 (0) | 2025.11.10 |
| [Java] 인스턴스 멤버와 정적 멤버 (0) | 2025.11.10 |
| [Java] 메소드 (0) | 2025.11.09 |