하위 클래스가 상위 클래스에 이미 정의된 메서드에 대한 특정 구현을 제공하는 경우 이를 메서드 재정의라고 합니다. 하위 클래스의 재정의된 메서드에는 상위 클래스의 메서드와 동일한 이름 매개 변수 및 반환 유형이 있어야 합니다.
메서드 재정의 규칙
- 이름 매개변수와 반환 유형은 상위 메소드와 일치해야 합니다.
- Java는 참조 변수 유형뿐만 아니라 실제 객체 유형을 기반으로 런타임에 실행할 메소드를 선택합니다.
- 정적 메서드는 재정의될 수 없습니다.
- 그만큼 @Override 주석 메소드 이름의 오타와 같은 실수를 잡아냅니다.
class Animal { void move(){ System.out.println( 'Animal is moving.'); } void eat(){ System.out.println( 'Animal is eating.'); } } class Dog extends Animal{ @Override void move(){ // move method from Base class is overriden in this // method System.out.println('Dog is running.'); } void bark(){ System.out.println('Dog is barking.'); } } public class Geeks { public static void main(String[] args) { Dog d = new Dog(); d.move(); d.eat(); d.bark(); } }
산출
Dog is running. Animal is eating. Dog is barking.
설명: Animal 클래스는 다음과 같은 기본 기능을 정의합니다. 이동하다() 그리고 먹다() . Dog 클래스는 Animal 및 재정의 특정 동작을 제공하는 move() 메서드 개가 달리고 있다. 두 클래스 모두 자체 메서드에 액세스할 수 있습니다. move()를 호출하는 Dog 객체를 생성할 때 재정의된 메서드가 실행됩니다.

재정의의 특수 사례
1. super를 사용하여 부모 메서드 호출
그만큼 슈퍼 키워드 재정의 메서드에서 상위 클래스 메서드를 호출할 수 있습니다.
Javaclass Parent{ void show(){ System.out.println('Parent's show()'); } } class Child extends Parent{ @Override void show(){ super.show(); System.out.println('Child's show()'); } } public class Main{ public static void main(String[] args){ Parent obj = new Child(); obj.show(); } }
산출
Parent's show() Child's show()
2. 최종 메서드는 재정의될 수 없습니다.
메서드를 재정의하지 않으려면 다음과 같이 선언합니다. 결정적인 . 참조하세요 상속과 함께 Final 사용 .
인접각Java
class Parent{ // Can't be overridden final void show(){ } } class Child extends Parent{ // This would produce error void show() {} }
산출 :
3. 정적 방법
- 정적 메서드는 재정의될 수 없습니다. 슈퍼클래스와 동일한 시그니처를 사용하여 하위 클래스에 정적 메서드를 정의하면 슈퍼클래스 메서드가 숨겨집니다.
- 인스턴스 메서드는 재정의될 수 있지만 하위 클래스는 슈퍼클래스의 정적 메서드를 재정의할 수 없습니다.
- 슈퍼클래스 정적 메서드와 동일한 시그니처를 가진 하위 클래스의 정적 메서드는 원래 메서드를 숨깁니다.
class Parent{ static void staticMethod(){ System.out.println('Parent static method'); } void instanceMethod(){ System.out.println('Parent instance method'); } } class Child extends Parent{ static void staticMethod(){ // Hides Parent's static method System.out.println('Child static method'); } @Override void instanceMethod(){ // Overrides Parent's instance method System.out.println('Child instance method'); } } public class GFG{ public static void main(String[] args){ Parent p = new Child(); // Calls Parent's static method (hiding) p.staticMethod(); // Calls Child's overridden instance method p.instanceMethod(); } }
산출
Parent static method Child instance method
4. 비공개 방법
- 프라이빗 메서드는 하위 클래스에 표시되지 않으므로 재정의할 수 없습니다.
- 동일한 이름을 가진 하위 클래스 메서드는 상위 클래스와 관련이 없는 새로운 독립 메서드로 처리됩니다.
class Parent{ private void display(){ System.out.println('Parent private method'); } } class Child extends Parent{ void display(){ // This is a new method not overriding System.out.println('Child method'); } } public class GFG{ public static void main(String[] args){ Child c = new Child(); // Calls Child's method c.display(); } }
산출
Child method
5. 공변 반환 유형
- 메서드 재정의에서 재정의 메서드의 반환 형식은 재정의된 메서드 반환 형식의 하위 클래스일 수 있습니다.
- 이 기능은 공변 반환 유형으로 알려져 있으며 하위 클래스에서 보다 구체적인 반환 유형을 허용합니다.
class Parent{ Parent getObject(){ System.out.println('Parent object'); return new Parent(); } } class Child extends Parent{ @Override // Covariant return type Child getObject() { System.out.println('Child object'); return new Child(); } } public class GFG{ public static void main(String[] args){ Parent obj = new Child(); // Calls Child's method obj.getObject(); } }
산출
Child object
재정의의 예외 처리
- 재정의 메서드는 슈퍼클래스의 메서드보다 새롭거나 더 광범위한 확인된 예외를 발생시킬 수 없습니다.
- 더 적거나 더 좁은 범위의 확인된 예외를 발생시킬 수 있습니다.
- 슈퍼클래스 메서드에 관계없이 확인되지 않은 예외(예: RuntimeException)가 발생할 수 있습니다.
import java.io.IOException; class Parent { void display() throws IOException { System.out.println('Parent method'); } } class Child extends Parent { @Override void display() throws IOException { System.out.println('Child method'); } } public class GFG{ public static void main(String[] args){ // Parent reference Child object Parent obj = new Child(); try{ // Calls Child's overridden method obj.display(); } catch (IOException e){ System.out.println('Exception caught: ' + e.getMessage()); } } }
산출
Child method
메소드 재정의를 사용하는 이유는 무엇입니까?
- 하위 클래스에 있는 기존 메서드의 동작을 변경하거나 향상시키는 것입니다.
- 런타임 다형성을 달성하기 위해 — 메소드 호출은 실제 객체 유형에 따라 달라집니다.
- 메소드 이름을 재사용하여 논리적으로 중복성을 줄입니다.
실제 사례: 직원 관리 시스템
실제 비유를 통해 재정의를 이해해 보겠습니다.
조직의 직원 관리 시스템을 상상해 보세요. 모든 직원은 raiseSalary() 및 Promotion()과 같은 일부 동작을 공유하지만 관리자 또는 엔지니어와 같은 역할에 따라 논리가 다릅니다. 개별 직원이 다양한 유형(영업 기술 등)인 단일 Employee 배열을 만들고 해당 기능을 호출할 수 있습니다. 이렇게 하면 전체 코드가 많이 단순화됩니다.
Javaabstract class Employee { abstract void raiseSalary(); abstract void promote(); } class Manager extends Employee{ @Override void raiseSalary(){ System.out.println( 'Manager salary raised with incentives.'); } @Override void promote(){ System.out.println( 'Manager promoted to Senior Manager.'); } } class Engineer extends Employee{ @Override void raiseSalary(){ System.out.println( 'Engineer salary raised with bonus.'); } @Override void promote(){ System.out.println( 'Engineer promoted to Senior Engineer.'); } } public class Company{ public static void main(String[] args){ Employee[] employees = { new Manager() new Engineer() }; System.out.println('--- Raising Salaries ---'); for (Employee e : employees){ e.raiseSalary(); } System.out.println('n--- Promotions ---'); for (Employee e : employees) { e.promote(); } } }
산출
--- Raising Salaries --- Manager salary raised with incentives. Engineer salary raised with bonus. --- Promotions --- Manager promoted to Senior Manager. Engineer promoted to Senior Engineer.
설명: Manager 및 Engineer 객체는 모두 Employee 유형을 사용하여 참조되지만 Java는 런타임 시 실제 객체의 재정의된 메소드를 호출하여 동적 메소드 디스패치(런타임 다형성)를 보여줍니다.
관련 기사: 메소드 오버로딩 및 메소드 오버라이딩