안녕하세요, 여행벌입니다.

오늘은 저번 포스팅 상속에 이어서 오버라이딩에 대해서 포스팅해보겠습니다.


메소드 오버라이딩(Overriding)

메소드 오버라이딩은 상위 클래스에 정의된 메소드를 하위 클래스에서 다시 정의하는 것을 뜻합니다.

 

 오버라이딩을 위해서는 메소드의 이름, 메소드의 반환형, 메소드의 매개변수 선언이 모두 같아야 합니다. 메소드 오버라이딩이 발생하면 자바는 상위 클래스의 메소드를 무효화시키고, 하위 클래스의 메소드를 살려둡니다.

 예시를 통해서 익혀보겠습니다.

package Hello;

class supClass{
	public supClass() {}; //생성자
	void sayHello() {
		System.out.println("supClass Hello");
	}
}

class subClass extends supClass{
	public subClass() {}; // 생성자
	void sayHello() {
		System.out.println("subClass Hello!!");
	}
}

public class test{
	public static void main(String args[]) {
		// supClass 참조변수가 supClass 인스턴스 --> 오버라이딩 X
		supClass class1 = new supClass();
		class1.sayHello();
		
		// supClass 참조변수가 subCLass 인스턴스 --> 오버라이딩 O
		supClass class2 = new subClass();
		class2.sayHello();
		
		// subClass 참조변수가 subClass 인스턴스 --> 오버라이딩 O
		subClass class3 = new subClass();
		class3.sayHello();
	}
}

 상위 클래스와 그 클래스를 상속하는 하위 클래스를 만들었습니다. 하지만, 상위 클래스와 하위 클래스에  반환형 / 메소드의 이름 / 메소드의 매개 변수가 모두 같은 sayHello 라는 메소드가 존재합니다. 

 

 저번 포스팅에서 상속을 진행하면 상위 클래스의 변수, 메소드가 모두 하위 클래스에게 전달된다고 얘기했습니다. 따라서, 같은 메소드가 동시에 2개 존재하는 상황이 발생합니다. 이때, 자바에서는 메소드 오버라이딩을 통해 상위 클래스의 메소드를 무효화시키고, 하위 클래스의 메소드만 남겨둡니다.

[Output]
supClass Hello
subClass Hello!!
subClass Hello!!

 그럼, 상위 클래스 메소드를 하위 클래스에서 사용하고 싶다면 어떻게 해야될까요? super 키워드를 이용하면 사용할 수 있습니다.

package Hello;

class supClass{
	public supClass() {}; //생성자
	void sayHello() {
		System.out.println("supClass Hello");
	}
}

class subClass extends supClass{
	public subClass() {}; // 생성자
	void sayHello() {
		super.sayHello();
		System.out.println("subClass Hello!!");
	}
}

public class test{
	public static void main(String args[]) {
		// subClass 참조변수가 subClass 인스턴스 --> 오버라이딩 O
		subClass class1 = new subClass();
		class1.sayHello();
	}
}

 다음과 같이 super 키워드를 이용하면 상위 클래스의 메소드 또한 이용할 수 있습니다.

인스턴스 변수, 클래스 변수, 클래스 메소드의 오버 라이딩

 그럼 인스턴스 메소드가 아닌 인스턴스 변수와 클래스 변수, 클래스 메소드도 오버 라이딩이 될까요?? 결론부터 얘기하면 오버라이딩 대상이 아닙니다.

 자바는 '참조변수의 형' 에 따라서 접근하는 변수가 결정되므로 클래스 변수, 클래스 메소드, 인스턴스 변수는 오버라이딩 되지 않습니다.

package Hello;

class supClass{
	int a = 1;
	static int b = 2;
	static void sayBye() {
		System.out.println("supClass Bye!!");
	}
	public supClass() {}; //생성자
	void sayHello() {
		System.out.println("supClass Hello");
	}
}

class subClass extends supClass{
	int a = -1;
	static int b = -2;
	static void sayBye() {
		System.out.println("subClass Bye!!");
	}
	
	public subClass() {}; // 생성자
	void sayHello() {
		super.sayHello();
		System.out.println("subClass Hello!!");
	}
}

public class test{
	public static void main(String args[]) {
		//supClass 참조변수가 supClass 인스턴스 참조
		supClass class1 = new supClass();
		System.out.println(class1.a + " " +  class1.b);
		class1.sayBye();
		
		// supClass 참조변수가 subClass 인스턴스 참조
		// 인스턴스 메소드였으면 원래 오버라이딩 되는 상황
		supClass class2 = new subClass();
		System.out.println(class2.a + " " + class2.b);
		class2.sayBye();
	}
}

 동일한 이름의 인스턴스 변수(a), 클래스 변수(b), 클래스 메소드(sayBye) 를 상위 클래스와 하위 클래스에서 모두 선언했습니다. 하지만, 오버라이딩 대상이 아니므로 결과는 다음과 같이 참조변수의 형에 따라서 supClass의 인스턴스 변수, 클래스 변수, 클래스 메소드를 참조하는 것을 알 수 있습니다.

[Output]
1 2
supClass Bye!!
1 2
supClass Bye!!

클래스와 메소드의 final 선언

 클래스와 메소드에 final 선언을 추가하면 해당 클래스 혹은 해당 메소드를 다른 클래스가 상속, 오버라이딩 하지 못하게 막을 수 있습니다. 대표적인 final 클래스로 String 클래스가 있습니다. 따라서, 우리는 String 클래스를 상속할 수 없습니다.

final class myClass { } // 다른 클래스가 상속할 수 없는 클래스

class myClass2{
	final void func(){ } // 메소드 오버라이딩을 할 수 없는 메소드
}

@Override

 자바 5에서 '어노테이션' 이 소개되었습니다. 그 중, 메소드 오버라이딩과 관련된 @Override 어노테이션에 대해서 알아보겠습니다.

 우리는 메소드 오버라이딩을 의도하고 코드를 구현했지만, 개발자의 실수로 오버라이딩 조건을 만족하지 못해서 오버라이딩이 진행되지 않는 상황이 발생할 수 있습니다.

package Hello;

class supClass{
	public supClass() {}; //생성자
	void add(int a, int b) {
		System.out.println(a + b);
	}
}

class subClass extends supClass{
	public subClass() {}; // 생성자
	// 메소드 오버라이딩
	void add(double a, double b) {
		System.out.println(a + b);
	}
	
}

public class test{
	public static void main(String args[]) {
		subClass class1 = new subClass();
		class1.add(5, 7);
	}
}

subClass 에서 supClass의 add 메소드를 오버라이딩 하려고 하였으나, 매개변수형이 int 형이 아닌 double 형이라 오버라이딩이 발생하지 않은 상황입니다. 이런 상황을 @Override 어노테이션을 통해서 해결할 수 있습니다.

class supClass{
	public supClass() {}; //생성자
	void add(int a, int b) {
		System.out.println(a + b);
	}
}

class subClass extends supClass{
	public subClass() {}; // 생성자
	// 메소드 오버라이딩
	@Override
	void add(double a, double b) {
		System.out.println(a + b);
	}
}

 @Override 어노테이션을 사용하면 자바 컴파일러에게 메시지를 전달할 수 있습니다. 즉, 나는 메소드 오버라이딩을 하고 싶어요! 라고 자바 컴파일러에게 전달하는 메시지입니다. 따라서, @Override 어노테이션을 오버라이딩을 원하는 메소드 위에 선언하면 반환형, 메소드의 이름, 매개 변수가 모두 같은 오버라이딩 가능한 메소드가 없다면 자바 컴파일러가 코드가 잘못 구현되었다고 알려줍니다.


 

+ Recent posts