회고록 블로그

[공부 필기] Java 기본 공부하기 (16) 본문

2. 프로그래밍 언어 공부/Java

[공부 필기] Java 기본 공부하기 (16)

김간장 2021. 11. 16. 20:58

공부 중인 강의 : 윤성우 선생님, 윤성우의 열혈 Java 프로그래밍 강의.

링크 : https://cafe.naver.com/cstudyjava

 

윤성우의 프로그래밍 스터디그룹 [C/... : 네이버 카페

윤성우의 스터디 공간입니다. C와 JAVA를 공부하시는 분들은 모두 들어오세요. ^^

cafe.naver.com

 


1. 메소드 오버라이딩 (이어서)

1) 오버라이딩 이해부터 하기

- 부모 클래스와 자식 클래스에 동일한 반환형+동일한 이름+동일한 파라미터인 메소드가 있다면?

   → 부모 객체의 메소드는 가려짐

   → 이렇게 자식 객체의 메소드가 부모 객체의 메소드를 가려버리는 것을 '오버라이딩'이라고 함

public class Coffee {
...
	void printRecipe() {
		System.out.println("샷 :"+shotCount+"만큼 첨가");
	}
...
public class CaramelMacchiato extends Coffee {
...
	void printRecipe() {
		System.out.println("우유 : "+milk+"만큼 첨가");
		System.out.println("카라멜시럽 : "+syrupCount+"만큼 첨가");		
	}
...

   → CaramelMacchiato의 printRecipe 메소드가 Coffee의 printRecipe 메소드를 오버라이딩 한 것

 

[그림1] 메인메소드 실행 결과

   → 두 인스턴스는 '오버라이딩 관계'라고 볼 수 있음

 

 

2) 그림1과 같은 상황이 나오는 이유

public class MainMethod {
	public static void main(String args[]) {
		Coffee order1 = new CaramelMacchiato(1, "오곡", 2);
		CaramelMacchiato order2 = new CaramelMacchiato(2, "무지방", 2);
		
		order1.printRecipe();
		System.out.println("------------------------------");
		order2.printRecipe();
	}
}

- order1은 참조타입이 Coffee(부모)이지만, 가리키는 대상은 CaramelMacchiato(자식)

- order2는 참조타입도, 실제 가리키는 대상도 모두 CaramelMacchiato(자식)

 

- 일반적으로 아래의 코드는 "부모 객체의 printRecipe 메소드가 출력"되어야 하지만, 자식 객체의 메소드가 출력되어버림

order1.printRecipe(); 
// 보통은 부모 객체(Coffee)의 printRecipe 메소드가 출력되어야 함
// 하지만, 출력되는 결과는 자식 객체(CaramelMacchiato)의 printRecipe 메소드임

   → 그 이유는 자식 인스턴스의 printRecipe 메소드가 부모 인스턴스의 printRecipe 메소드를 가려버려서(= 오버라이딩)

         자식 인스턴스의 printRecipe 메소드가 대신 호출됐기 때문

   → 이 경우가 바로 '메소드 오버라이딩'

 

 

3) 주의사항

- 참조타입도 Coffee, 실제 가리키고 있는 인스턴스도 Coffee인 경우는 메소드 오버라이딩이 아님

   → 이 경우는 애초에 자식 객체(CaramelMacchiato)가 메모리에 올라가지도 않았음

Coffee order3 = new Coffee(2);

- 예전에 사용했던 StringBuilder 클래스에도 toString 메소드가 존재했는데 사실 이것도 '메소드 오버라이딩'이라고 볼 수 있을 듯

   → StringBuilder의 toString 메소드가 Object 클래스에 toString 메소드를 가려버린 경우

- 인스턴스 변수는 오버라이딩이 되지 않음

   → 부모 클래스와 자식 클래스에 같은 이름의 변수가 있다고 해도 오버라이딩 되지 않음

   → 인스턴스 메소드만 오버라이딩이 가능함

   → 그리고, 부모 클래스와 자식 클래스에 "동일한 이름의 변수"를 선언하는게 좋은 코드는 아님

 

 

4) 부모 클래스의 메소드를 호출하려면?

- 자식 클래스의 내부에서 super 키워드를 이용해서 멤버 메소드에 접근하면 됨

- 하지만, 외부에서 부모 클래스의 메소드에 접근할 수는 없음(오버라이딩 되었기 때문)

 

2. instanceof 연산자

- instanceof 연산자의 반환값은 true/false

- "참조변수"가 "클래스이름"의 인스턴스를 참조하면 true를 반환하고,

   "참조변수"가 "클래스이름"을 상속하는 클래스의 인스턴스이면 true를 반환

- instanceof 연산자의 오른쪽에는 참조타입이나 패턴이 올 수 있음

출처: https://docs.oracle.com/javase/specs/jls/se16/html/jls-15.html#jls-15.20.2

- 이해를 위한 예시

   → 아래와 같이 상황을 가정

가정 상황

   → 메인 메소드에는 이러한 코드가 존재한다고 가정

public class MainMethod {
	public static void main(String args[]) {
		Product fridge = new Refrigerator();

		if(fridge instanceof Refrigerator) {
			System.out.println("true");
		}
	}
}

   → 실행 결과는 "true"가 됨

   → 여기에서 instanceof 연산자는 "fridge 참조변수가 참조타입으로 Refrigerator를 가질 수 있는지"를 묻는 것임

   → fridge가 가리키는 인스턴스가 Refrigerator이기 때문에 참조타입으로 모두(Product, HomeAppliance, Refrigerator) 올 수 있음

현재 상황을 그림으로 표현

- 사실 instanceof 연산자를 많이 사용하지는 않는다고 함

 

# 번외

public class MainMethod {
	public static void main(String args[]) {
		HomeAppliance fridge = new Refrigerator();
		
		if(fridge instanceof Refrigerator) {
			System.out.println("Refrigerator true");
		}
		
		if(fridge instanceof HomeAppliance) {
			System.out.println("HomeAppliance true");
		}
		
		if(fridge instanceof Product) {
			System.out.println("Product true");
		}
	}
}

- 위의 코드의 결과는? 모두 true

   → 참조변수 fridge가 가리키는 인스턴스가 Refrigerator 이기 때문

 

public class MainMethod {
	public static void main(String args[]) {
		Product fridge = new HomeAppliance();
		
		if(fridge instanceof Refrigerator) {
			System.out.println("Refrigerator true");
		}
		
		if(fridge instanceof HomeAppliance) {
			System.out.println("HomeAppliance true");
		}
		
		if(fridge instanceof Product) {
			System.out.println("Product true");
		}
	}
}

- 위의 코드의 결과는? 두번째 if문과 세번째 if문만 true

   → 참조변수 fridge가 가리키는 인스턴스가 HomeAppliance 이기 때문에 fridge의 참조타입은 Product이거나 HomeAppliance 밖에 안됨

 

Comments