본문 바로가기

자바/자바 개념

[Java] 메소드 오버라이딩 / 2021.11.02

1. 메소드 오버라이딩이란?

메소드 오버라이딩은 슈퍼 클래스와 서브 클래스의 메소드 사이에 발생하는 관계이다.

슈퍼 클래스에 선언된 메소드와 같은 이름, 같은 리턴 타입, 같은 매개변수 리스트를 갖는 메소드를 서브 클래스에서 재작성하는 것이다.

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

 

예시를 통해서 알아보자. 

아래의 코드는 Shape 클래스를 상속받은 3개의 클래스 Line, Rect, Circle클래스를 만들고, Shape의 draw()를 오버라이딩한 코드이다. 메소드의 이름, 리턴 타입, 매개변수 리스트는 모두 동일하다.

 

package Chapter5;

class Shape{ // 슈퍼 클래스
	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" 출력

	}

}

 

paint() 메소드를 호출할 때 각 클래스에서 오버라이딩한 draw()를 실행한다.

 

실행결과 : 

 

2. 메소드 오버라이딩의 제약 사항

(1). 슈퍼 클래스의 메소드와 동일한 원형으로 작성한다.

(2). 슈퍼 클래스 메소드의 접근 지정자보다 접근의 범위를 좁혀 오버라이딩 할 수 없다. 

접근 지정자는 public, protected, 디폴트, private 순으로 접근의 범위가 좁아진다. 슈퍼 클래스에 protected로 선언된 메소드는 서브 클래스에서 protected나 public으로만 오버라이딩할 수 있고, public으로 선언된 메소드는 서브 클래스에서 public으로만 오버라이딩할 수 있다.

(3). static이나 private 또는 final로 선언된 메소드는 서브 클래스에서 오버라이딩할 수 없다.

 

3. 동적 바인딩: 오버라이딩된 메소드 호출

동적 바인딩은 실행할 메소드를 컴파일 시에 결정하지 않고 실행 시 결정하는 것을 말한다.

자바에서는 동적 바인딩을 통해 오버라이딩된 메소드가 항상 실행되도록 보장한다.

 

아래의 코드를 보자.

Circle 클래스에서 Shape의 draw()를 오버라이딩하였다. main()에서 Circle 객체를 생성하고 b.paint()를 호출하면, 객체 b에 존재하는 2개의 draw() 중 어떤 것을 호출할지 결정하는 동적 바인딩이 일어난다.

그 결과 Shape의 paint()메소드는 Shape의 draw()가 아닌, Circle의 draw()를 호출한다. Shape에서 호출하든 Circle에서 호출하든, draw()가 호출되면 동적 바인딩을 통해 항상 오버라이딩한 Circle의 draw()가 호출된다.

* 어떤 경우이든 자바에서 오버라이딩된 메소드가 있다면 동적 바인딩을 통해 오버라이딩된 메소드가 무조건 실행된다.

 

class Shape{
	protected String name;
    public void paint(){
    	draw();
    }
    public void draw(){
    	System.out.println("Shape");
    }
}

public class Circle extends Shape{
	public void draw(){
    	System.out.println("Circle");
    }
    public static void main(String[] args){
    	Shape b = new Circle();
        b.paint();
    }
}

 

동적 바인딩

 

4. 오버라이딩과 super 키워드

메소드가 오버라이딩되어 있는 경우, 동적 바인딩에 의해 항상 서브 클래스에 오버라이딩한 메소드가 호출된다고 하였다. 하지만 super키워드를 사용한다면 정적 바인딩을 통해 슈퍼 클래스의 멤버에 접근할 수 있다.

 

super.슈퍼클래스의 멤버

 

아래의 코드를 실행해보면 2개의 name필드에 각각 다른 문자열이 들어 있는 것을 볼 수 있다.

 

class Shape{
	protected String name;
    public void paint(){
    	draw();
    }
    public void draw(){
    	System.out.println(name);
    }
}

public class Circle extends Shape{
	protected String name;
	public void draw(){
    	name = "Circle";
        super.name = "Shape";
        super.draw();
    	System.out.println(name);
    }
    public static void main(String[] args){
    	Shape b = new Circle();
        b.paint();
    }
}

 

super() 정적 바인딩

5. 오버로딩(overloading)과 오버라이딩(overriding)

 

비교 요소 메소드 오버로딩 메소드 오버라이딩
선언 같은 클래스나 상속 관계에서 동일한 이름의 메소드 중복 작성 서브 클래스에서 슈퍼 클래스에 있는 메소드와 동일한 이름의 메소드 재작성
관계 동일한 클래스 내 혹은 상속 관계 상속 관계
목적 이름이 같은 여러 개의 메소드를 중복 작성하여 사용의 편리성 향상, 다형성 실현 슈퍼 클래스에 구현된 메소드를 무시하고 서브 클래스에서 새로운 기능의 메소드를 재정의 하고자 함. 다형성 실현
조건 메소드 이름은 반드시 동일하고, 매개변수 타입이나 개수가 달라야 성립 메소드의 이름, 매개변수 타입과 개수, 리턴 타입이 모두 동일하여야 성립
바인딩 정적 바인딩. 호출될 메소드는 컴파일 시에 결정 동적 바인딩. 실행 시간에 오버라이딩된 메소드 찾아 호출