메소드 오버라이딩
메소드 오버라이딩의 개념
슈퍼 클래스와 서브 클래스의 메소드 사이에 발생하는 관계로서, 슈퍼 클래스에 선언된 메소드와 같은 이름, 같은 리턴 타입, 같은 매개 변수 리스트를 갖는 메소드를 서브 클래스에서 재작성하는 것입니다.
서브 클래스의 개발자는 슈퍼 클래스에 있는 메소드로 목적하는 바를 이룰 수 없을 떄 동일한 이름의 메소드를 서브 클래스에 다시 작성할 수 있습니다.

메소드 오버라이딩은 '슈퍼 클래스 메소드 무시하기 혹은 덮어쓰기'로 표현할 수 있습니다. 이는 슈퍼 클래스의 메소드를 무시하고 서브 클래스에서 오버라이딩된 메소드가 무조건 실행되도록 한다는 것인데, 이런 처리를 동적 바인딩이라고 부르며, 메소드 오버라이딩을 유발시킵니다.
오버라이딩 사례로 이해하기

오버라이딩된 메소드 호출
Line line = new Line();
line.draw();
레퍼런스 line이 Line 타입이므로, 컴파일러는 당연히 line.draw()가 Line 클래스의 draw() 메소드를 호출하도록 하고 실행 시에도 Line 클래스의 draw()가 호출됩니다.
Shape shape = new Line(); // 업캐스팅
shape.draw();
이 경우에도 new Line()에 의해 생성된 Line 객체에는 2개의 draw() 메소드의 존재하지만, 첫 번째 경우와 다른 것은, 레퍼런스 shape이 Shape 타입입니다.
그러므로 shape.draw()를 컴파일할 때, 컴파일러는 Shape 클래스에 draw() 멤버가 있는지 확인하고 Shape의 draw()를 호출하도록 컴파일합니다.
하지만, shape.draw()의 실행 시 shape의 가리키는 객체에는 Shape의 draw()를 오버라이딩한 Line의 draw()가 존재하기 때문에, Shape의 draw()가 아닌 Line의 draw()가 실행됩니다.
이 과정을 동적 바인딩(dynamic binding)이러 부릅니다.

오버라이딩 목적, 다형성 실현
오버라이딩은 슈퍼 클래스에 선언된 메소드를, 각 서브 클래스들이 자신만의 내용으로 새로 구현하는 기능입니다.
오버라이딩은 상속을 통해 '하나의 인터페이스(같은 이름)에 서로 다른 내용 구현'이라는 객체 지향의 다형성을 실현하는 도구입니다.
메소드 오버라이딩으로 다형성 실현
class Shape { // 슈퍼 클래스
public Shape next;
public Shape() { next = null; }
public void draw() {
System.out.println("Shape");
}
}
class Line extends Shape {
public void draw() { // 메소드 오버라이딩
System.out.println("Line");
}
}
class Rect extends Shape {
public void draw() { // 메소드 오버라이딩
System.out.println("Rect");
}
}
class Circle extends Shape {
public void draw() {
System.out.println("Circle");
}
}
public class MethodOverridingEx {
static void paint(Shape p) {
p.draw(); // p가 가리키는 객체 내에 오버라이딩된 draw() 호출. 동적 바인딩
}
public static void main(String[] args) {
Line line = new Line();
// 다음 호출둘은 모두 paint() 메소드 내에서 Shape에 대한 레퍼런스 p로 업캐스팅
paint(line); // Line에 오버라이딩한 draw() 실행, "Line" 출력
paint(new Shape()); // Shape의 draw() 실행. "Shape" 출력
paint(new Line()); // Line에 오버라이딩한 draw() 실행, "Line" 출력
paint(new Rect()); // Rect에 오버라이딩한 draw() 실행, "Rect" 출력
paint(new Circle()); // Circle에 오버라이딩한 draw() 실행, "Circle" 출력
}
}
실행결과
Line
Shape
Line
Rect
Circle

메소드 오버라이딩의 제약 사항
슈퍼 클래스의 메소드와 동일한 원형으로 작성합니다.
슈퍼 클래스의 메소드와 동일한 이름, 동일한 매개변수 타입과 개수, 동일한 리턴 타입를 갖는 메소드를 작성해야 합니다.
class Line extends Shape {
public int draw() { // 컴파일 오류. 리턴 타입이 달라 오버라이딩 실패
return 5;
}
}
슈퍼 클래스 메소드의 접근 지정자보다 접근의 범위를 좁여 오버라이딩 할 수 없습니다.
접근 지정자는 pubic, procted, 디폴트, private 순으로 접근의 범위가 좁아집니다. 슈퍼 크래스에 protected로 선언된 메소드는 서브 클래스에서 protected나 public으로만 오버라이딩할 수 있고, public으로 선언된 메소드는 서브 클래스에서 public으로만 오버라이딩할 수 있습니다.
static이나 private 또는 final 로 선언된 메소드는 서브 클래스에서 오버라이딩할 수 없습니다.
메소드 오버라이딩 활용
메소드 오버라이딩은 서버 클래스 개발자가 슈퍼 클래스의 특정 메소드를 자신의 특성에 맞게 새로 만들어 사용하고자 하는 경우에 활용됩니다.
Shape p = start;
while(p != null) {
p.draw(); // p가 가리키는 객체의 오버라이딩된 draw() 메소드 호출
p = p.next(); // p가 다음 객체의 레퍼런스 값을 가짐
}
레퍼런스는 p의 타입이 Shape이므로 p.draw()는 Shape의 멤버 draw()를 호출하게 될 것 같지만, 실제로는 오버라이딩한 draw() 메소드가 호출됩니다. 이것을 통해 바인딩이라 합니다.

동적 바인딩: 오버라이딩된 메소드 호출
동적 바인딩(dynamic binding)은 실행할 메소드를 컴파일 시(compile time)에 결정하지 않고 실행 시(run time)에 결정하는 것을 말합니다. 자바에서는 동적 바인딩을 통해 오버라이딩된 메소드가 항상 실행되도록 보장합니다.
Shape a = new Shape();
a.paint(); // paint()는 Shape의 draw()를 호출합니다.

어떤 경우이든 자바에서 오버라이딩된 메소드가 있다면 동적 바인딩을 통해 오버라이딩된 메소드가 무조건 실행됩니다.
오버라이딩과 super 키워드
서브 클래스에서 super 키워드를 이용하면 정적 바인딩을 통해 슈퍼 클래스의 멤버에 접근할 수 있습니다.
| super.슈퍼클래스의멤버 |
super는 자바 컴파일러에 의해 지원되는 것으로 슈퍼 클래스에 대한 레퍼런스입니다.
name = "Circle"; // Circle 클래스의 name에 "Circle" 기록
super.name = "Shape"; // Shape 클래스의 name에 "Shape" 기록
super.draw(); // Shape 클래스의 draw() 호출. 정적 바인딩

메소드 오버라이딩
class Weapon {
protected int fire() {
return 1; // 무기는 기본적으로 한 명만 실상
}
}
class Cannon extends Weapon {
@Override
protected int fire() { // 오버라이딩
return 10; // 대포는 한 번에 10명을 실상
}
}
public class Overriding {
public static void main(String[] args) {
Weapon weapon;
weapon = new Weapon();
System.out.println("기본 무기의 살상 능력은 " + weapon.fire());
weapon = new Cannon();
System.out.println("대포의 살상 능력은 " + weapon.fire());
}
}
실행 결과
기본 무기의 살상 능력은 1
대포의 살상 능력은 10
오버로딩(overloading)과 오버라이딩(overriding)
| 비교 요소 | 메소드 오버로딩 | 메소드 오버라이딩 |
| 선언 | 같은 클래스나 상속 관계에서 동일한 이름의 메소드 중복 작성 | 서브 클래스에서 슈퍼 클래스에 있는 메소드와 동일한 이름의 메소드 재작성 |
| 관계 | 동일한 클래스 내 혹은 상속 관계 | 상속 관계 |
| 목적 | 이름이 같은 여러 개의 메소드를 중복 작성하여 사용의 편리성 향상. 다형성 실현 | 슈퍼 클래스에 구현된 메소드를 무시하고 서브 클래스에서 새로운 기능의 메소드를 재정의하고자 함. 다형성 실현 |
| 조건 | 메소드 이름은 반드시 동일하고, 매개 변수 타입이나 개수가 달라야 성립 | 메소드의 이름. 매개변수 타입의 개수, 리턴 타입이 도무 동일하여야 성립 |
| 바인딩 | 정적 바인딩, 호출될 메소드는 컴파일 시에 결정 | 동적 바인딩. 실행 시간에 오버라이딩된 메소드 찾아 호출 |
'프로그래밍 언어 > JAVA' 카테고리의 다른 글
| 인터페이스 (1) | 2025.02.16 |
|---|---|
| 추상 클래스 (0) | 2025.02.13 |
| 업캐스팅과 instanceof 연산자 (0) | 2025.02.09 |
| 상속과 생성자 (0) | 2025.02.08 |
| 상속과 protected 접근 지정자 (0) | 2025.02.07 |