티스토리 뷰
<상속>
기존의 클래스를 확장하여 새로운 클래스를 정의하는 매커니즘
기존 클래스의 속성과 메서드를 재사용하고 확장하여 새로운 클래스를 만들 수 있음.
상속에서는 두 개의 클래스가 필요함 부모 클래스(슈퍼 클래스): 기존에 정의된 클래스로, 상속의 대상이 되는 클래스 (부모 클래스의 속성과 메서드를 자식 클래스에게 상속함) 자식 클래스(서브 클래스): 부모 클래스를 확장하여 새롭게 정의되는 클래스 (부모 클래스의 모든 속성과 메서드를 상속 받음) |
예시
public class A {
String name;
int height;
int weight;
int age;
}
class B { // 접근제어 지시자 : default
String name;
int height;
int weight;
int age;
int level;
String nickName;
}
// 상속할 때 extends 사용(A가 부모, C가 자식/ C가 A로부터 상속 받은 후 기능적으로 확장되서 크기가 크다.)
class C extends A { // 클래스 C가 A로부터 상속 받음
int level;
String nickName;
String phone;
}
하나의 자바 파일 안에 여러 개의 클래스를 작성할 수 있다
단, public 이 붙은 클래스는 오직 하나만 정의 가능하다
public class CTest {
public static void main(String[] args) {
C c = new C(); // A의 상속을 받은 C 의 객체를 생성
c.name = "A"; // 객체의 변수명을 통해 객체에 접근함. C는 A의 상속을 받아서 .name은 A의 name이다.
System.out.println(c.name); //A가 출력됨
} // end of main
} // end of class
부모 생성자 호출
- 자식 객체를 생성하면 부모 객체가 먼저 생성된 다음에 자식 객체가 생성된다.
- 모든 객체는 생성자를 호출해야만 생성된다.
- 부모 생성자는 자식 생성자의 super()에 의해 호출된다. (super()는 컴파일 과정에서 자동 추가된다. 이는 부모의 기본 생성자를 호출한다.)
- 부모 클래스에 기본 생성자가 있다면 super(); 는 생략 가능하다.
- 만약 부모의 클래스에 기본 생성자가 없다면 자식 생성자 선언에서 컴파일 에러가 발생한다.
- 부모 클래스에 기본 생성자가 없고 매개변수를 갖는 생성자만 있다면 super(매개값, ...) 코드를 반드시 작성해야 한다.
// 자식 생성자 선언
public 자식 클래스(...){
super();
...
}
public 자식 클래스(...){
super(매개값, ...);
...
}
자식 객체를 생성하면 부모 객체가 먼저 생성된 다음에 자식 객체가 생성된다.
=> 이 부분을 좀 더 알아보자
자식클래스 변수 = new 자식클래스();
이 코드는 자식클래스 객체만 생성된 것처럼 보이지만, 사실은 부모 객체가 먼저 생성된 다음에 자식 객체가 생성된 것이다.
<오버라이드>
상속관계에서 부모 클래스에 정의된 메서드를 자식 클래스에서 재정의(다시 정의)하는 것
(이유: 부모 클래스의 메서드가 자식 클래스가 사용하기에 적합하지 않기 때문)
자식 클래스에서 부모 클래스의 메서드를 새로운 내용으로 구현하는 것
=> 자식 클래스는 부모 클래스의 메서드를 덮어쓰게 되어(숨겨짐) 부모 클래스의 메서드
대신 자식 클래스에서 정의한 메서드가 우선적으로 호출됨.
메서드 오버라이딩 시 규칙
|
예시1)
public class Cal {
public Cal() {
System.out.println("Cal() 부모 생성자 호출");
}
public int sum(int n1, int n2) {
return n1 + n2;
}
public int multiply(int n1, int n2) {
System.out.println("2. 호출");
System.out.println("여기는 부모 클래스 메서드 입니다.");
return n1 * n2;
}
// 코드 테스트
public static void main(String[] args) {
Cal2 cal2 = new Cal2(); // 메모리에 자식(cal2)만 올림
// heap 메모리에 먼저 부모 클래스가 태어난 후 자동으로 자식이 올라옴.
System.out.println(cal2.sum(5, 3));
System.out.println(cal2.minus(10, 3));
System.out.println(cal2.multiply(10, 0));
}
}
class Cal2 extends Cal {
public Cal2() {
System.out.println("Cal2() 자식 생성자 호출");
}
public int minus(int n1, int n2) {
return n1 - n2;
}
@Override // <- 오버라이드된 메서드다
public int multiply(int n1, int n2) {
System.out.println("1. 호출");
return super.multiply(n1, n2); //this 대신에 super.(부모 클래스의 객체)로 부모의 메서드를 호출함
}
class Cal에 메인 함수가 있으며 코드 테스트 한 결과
Cal2만 객체를 생성하였지만 출력은 Cal() 부모 생성자 호출이 먼저 출력된 후 Cal2() 자식 생성자 호출이 출력된다.
이는 heap 메모리에 먼저 부모 클래스가 태어난 후 자동으로 자식이 올라와서 이다.
Cal을 상속받은 Cal2가 Cal 의 sum 메서드를 호출하여 출력하면 8(5+3)이 출력된다.
다음으로 Cal2가 minus 메서드를 호출하여 7(10-3)이 출력된다.
Cal2의 multiply 메서드를 호출하면 Cald의 메서드가 아닌 오버라이드된 Cal2 의 메서드가 호출된다.
그러므로 1. 호출이 먼저 출력되고, return 값으로 super(Cal)의 multifly 메서드가 호출되어 2. 호출이 출력되고
return 값 0(10*0)이 출력된다.
추가로 Cal2 가 Cal 로부터 상속받음으로써 Cal2클래스는 Cal 클래스라고도 할 수 있다. 이를 다형성이라고 한다.
예시2)
부모 클래스 생성
public class Hero {
String name;
int hp;
public Hero() {
} // 부모 클래스가 메모리에 먼저 떠야 함. -> 자식 생성자 먼저 만들어야 함.
public Hero(String name, int hp) {
this.name = name;
this.hp = hp;
}
void attack() {}
}
자식 클래스(Warrior) 생성
public class Warrior extends Hero{
public Warrior(String name, int hp) { // 호출한 내용을 받을 수 있도록 매개변수 똑같이 입력하기
super(name, hp); // super로 부모 생성자 호출
}
// 오버라이드
@Override
void attack() {
System.out.println("전사가 기본 공격을 합니다.");
}
void comboAttack() {
System.out.println("전사가 2단 공격을 합니다.");
}
}
자식 클래스(Archer) 생성
public class Archer extends Hero {
public Archer(String name, int hp) {
super(name, hp);
}
@Override
void attack() {
System.out.println("궁수가 기본 공력을 합니다.");
}
void fireArrow() {
System.out.println(name + " 가 불화살 공격을 합니다");
}
}
자식 클래스(Wizard) 생성
public class Wizard extends Hero {
public Wizard(String name, int hp) {
super(name, hp); // 부모 생성자 호출
}
@Override
void attack() {
System.out.println("마법사가 기본 공격을 합니다.");
}
void freezing() {
System.out.println("마법사가 얼음 공격을 합니다");
}
}
테스트 파일 생성
public class HeroTest {
public static void main(String[] args) {
Hero hero = new Hero("영웅", 100);
Warrior warrior1 = new Warrior("야스오", 100);
Archer archer1 = new Archer("애쉬", 100);
Wizard wizard = new Wizard("라이즐", 100);
warrior1.attack();
}
}
부모 메서드 호출
메서드를 재정의하면, 부모 메서드는 숨겨지고 자식 메서드만 사용되기 때문에 비록 부모 메서드의 일부만 변경된다 하더라도 중복된 내용을 자식 메서드도 가지고 있어야 한다. 이 문제는 공동 작업 처리 기법을 이용하면 해결된다.
자식 메서드 내에서 부모 메서드를 호출하는 방법이며 super 키워드와 . 연산자를 사용하면 숨겨진 부모 메서드를 호출 할 수 있다. (부모 메서드를 재사용함으로써 자식 메서드의 중복 작업 내용을 없애는 효과를 가져온다.)
class Parent{
public void method() {
// 작업 처리 1
}
}
class Child extends Parent{
// 재정의된 메서드
@Override
public void method() {
super.method(); // 부모(Parent class)의 method() 메서드 호출
// 작업 처리2
}
}
오버로드와 오버라이드의 차이는?
'Java' 카테고리의 다른 글
Java(다형성, 업/다운캐스팅) (0) | 2024.04.24 |
---|---|
Java( 포함관계, 연관, 의존관계) (0) | 2024.04.24 |
Java(배열, 메서드 오버로딩, 생성자 오버로딩) (0) | 2024.04.23 |
Java(this, static) (0) | 2024.04.18 |
Java(접근 제어 지시자/ getter와 setter) (0) | 2024.04.17 |