1. 메서드 오버라이딩의 개념과 동작
1) 메서드 오버라이딩 (overriding)
- 부모 클래스에게 상속받은 메서드와 동일한 이름의 메서드를 재정의하는 것
- 부모의 메서드를 자신이 만든 메서드로 덮어씀
- 조건
● 부모 클래스의 메서드와 시그너치 및 리턴 타입이 동일해야 함
● 부모 클래스의 메서드보다 접근지정자의 범위가 같거나 넓어야 함
2) 클래스 A와 B의 상속관계 및 print() 메서드의 오버라이딩
class A {
void print() {
System.out.println("A 클래스");
}
}
class B extends A {
void print() { //print() 메서드 재정의 -> 오버라이딩
System.out.pritnln("B클래스");
}
● A aa = new A()
- aa.print() ; -> A클래스
- 힙 메모리에 A() 생성자로 객체가 생성, 이를 A타입으로 선언한 참조 변수 aa는 이 객체를 가리킴
- 객체 내의 메서드 : 실제 메서드의 위치 정보 저장
- 실제 print()는 메서드 영역에 정의
● B bb = new B()
- bb.print(); -> B클래스
- 부모 클래스인 객체(A 객체)가 힙 메모리에 먼저 생성되므로 A 객체 내의 print()가 메서드 영역에 생성
- B 객체의 print() 역시 메서드 영역에 저장 -> 이미 A 객체를 생성하는 과정에서 print()메서드가 존재하고 있는 상황
- B 객체의 print() 메서드가 이미 있는 A객체의 print()를 오버라이딩
- 메서드 영역의 print()메서드는 이미 B의 print() 메서드로 오버라이딩된 이후이므로 "B클래스"출력
● A ab = new B ()
- ab.print(); -> B 클래스
- B() 생성자로 객체 생성하고 A타입으로 참조 변수 선언
- 부모 클래스 A객체가 만들어지고, 이후 B의 객체가 만들어짐
- 메서드 영역에서는 print() 메서드의 오버라이딩 발생
- A 타입의 참조 변수를 사용하고 있으므로 참조변수는 A객체를 가리키고 있음
- B의 print()로 오버라이딩된 이후이므로 A 객체 내부의 print()가 실행됐는데도 "B 클래스"출력
3. 메서드 오버라이딩을 사용하는 이유
class Animal {
void cry() {
}
}
class Bird extends Animal {
void cry() {
System.out.println("짹짹");
}
}
class Cat extends Animal {
void cry() {
System.out.println("야옹");
}
}
class Dog extends Animal {
void cry() {
System.out.println("멍멍");
}
}
- 4개의 클래스 모두 cry() 메서드를 포함
- 각각의 타입으로 선언 + 각각의 타입으로 객체 생성
Animal aa = new Animal();
Bird bb = new Bird();
Cat cc = new Cat();
Dog dd = new Dog();
aa.cry(); //출력없음
bb.cry(); //짹짹
cc.cry(); //야옹
dd.cry(); //멍멍
- 부모 클래스 타입으로 선언 + 각각의 타입으로 객체 생성
Animal ab = new Bird();
Animal ac = new Cat();
Animal ad = new Dog();
ab.cry(); //짹쨱
ac.cry(); //야옹
ad.cry(); //멍멍
- 참조 변수 ab,ac,ad는 모두 Animal 타입이지만 , 각각 서로 다른 메서드로 오버라이딩 -> cry() 메서드는 서로 다른 출력
- 다형적 표현으로 자식 클래스들의 객체를 부모 클래스인 Animal 타입으로 선언할 수 있음 -> Animal 내부의 메서드만 사용 가능
- Animal 클래스 내부의 cry()메서드가 없었다면 모든 참조 변수 cry() 호출 불가
- 부모 클래스 에 선언한 cry() 메서드 용도 : 자식 클래스에서 호출하기 위해서
- 배열로 한번에 관리 가능
Animal[] animals = new Animal[] {new Bird(), new Cat(), new Dog() };
for(Animal animal : animals) {
animal.cry();
} //쨱짹, 야옹, 멍멍
3. 메서드 오버라이딩과 메서드 오버로딩
1) 오버로딩(overloading)
- 이름이 동일하지만, 시그니처가 다른 여러 개의 메서드를 같은 공간에 정의
- 파일명은 동일하지만, 확장명이 다른 파일(abc.jpg, abc.png,...)을 같은 폴더에 복사
2) 오버라이딩(overriding)
- 파일명과 확장명이 완벽하게 동일한 파일을 같은 공간에 복사
package Inheritance;
class A {
void print1() {
System.out.println("A 클래스 print1");
}
void print2() {
System.out.println("A 클래스 print2");
}
}
class B extends A {
@Override
void print1() {
System.out.println("B 클래스 print1");
}
void print2(int a) {
System.out.println("B 클래스 print2");
}
}
public class MethodOverriding {
public static void main(String[] args) {
//A 타입 선언 / A 생성자 사용
A aa = new A();
aa.print1();
aa.print2();
System.out.println();
//B 타입 선언/ B 생성자 사용
B bb = new B();
bb.print1();
bb.print2();
bb.print2(3);
System.out.println();
//A 타입 선언/B 생성자 사용
A ab = new B();
ab.print1();
ab.print2();
}
}
- 클래스 A : print1() , print2() 메서드
- 클래스 B : 클래스 A를 상속 , print1()와 print2(int a) 를 추가로 정의
- print1()은 상속받은 메서드와 리턴 타입과 시그니처가 완벽하게 동일하므로 오버라이딩
- A에게 상속받은 print2() : 입력매개변수가 없음
B에서 추가로 정의한 print2(int a) : int형 입력매개변수 존재
=> 메서드 시그니처가 다름 (오버로딩)
- 클래스 B 내부에서는 print1(), print2(), print2(int a)메서드 사용 가능
4. 메서드 오버라이딩과 접근 지정자
- 자식 클래스가 부모 클래스의 메서드를 오버라이딩할 때는 접근지정자의 범위를 좁힐 수 없음
- 메서드 오버라이딩할 때 사용할 수 있는 접근 지정자
부모 클래스 메서드의 접근지정자 | 메서드 오버라이딩을 할 떄 사용할 수 있는 접근지정자 |
public | public |
protected | public, protected |
default | public, protected, default |
private | public, protected, default, private |
'Java > 문법' 카테고리의 다른 글
10 - 5장 super 키워드와 super() 메서드 (0) | 2023.06.01 |
---|---|
10-4장 인스턴스 필드와 정적 멤버의 중복 (0) | 2023.06.01 |
10-2장 객체의 타입 변환 (0) | 2023.05.04 |
10-1장 클래스 상속의 개념과 문법적 특징 (0) | 2023.05.04 |
9-2장 static 제어자 (0) | 2023.04.30 |