회고록 블로그

[Java 공부하기] clone 메소드를 오버라이딩 해서 사용해야하는 이유에 대해서 찾아보기 본문

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

[Java 공부하기] clone 메소드를 오버라이딩 해서 사용해야하는 이유에 대해서 찾아보기

김간장 2021. 12. 6. 21:32

clone 메소드를 공부하다가 멘붕이 와서 한번 정리하기로 했다.

 

 

일단 clone 메소드는 Object의 메소드이며, 접근수준 지시자는 protected이다.

 

이 clone 메소드를 다른 클래스에서 사용하려면 Cloneable 인터페이스를 구현해야하고, 오버라이딩해서 사용해야한다.

바로 아래처럼.

 

근데 여기에서 이해가 가지 않는 부분이 생겼다.

 

일단 위의 두 클래스는 다른 패키지에 존재하지만 모든 클래스는 Object 클래스를 상속한다.

 

그렇다면 Object 클래스의 clone 메소드 접근수준 지시자가 protected이니까,

다른 패키지에 있어도 (자식클래스이기 때문에) 바로 접근할 수 있는게 아닌가?

* protected 접근수준지시자는 같은 패키지이면 접근 가능 + 다른 패키지여도 상속 관계면 접근 가능이니까 말이다.

 

 

그래서 Fish 클래스에서 오버라이딩한 clone 메소드를 지워봤다.

(Object에 정의되어 있는 clone 메소드에 접근하기 위해서)

 

하지만 clone 메소드가 보이지 않는다며 에러가 발생했다.

 

분명 안되는 이유가 배운 내용 중에 있는 것 같은데 그게 뭔지 알 수가 없어서 하나씩 찾아보기로 했다.

 

※ Java 문법에 대한 이해가 부족한 초급자이기 때문에 틀린 내용이 있을 수 있습니다.


우선 내가 잘못 알고 있는 부분이 무엇인지 명확하게 찾을 필요가 있었다.

protected 부터 확인해보기로 했다.

 

protected 접근수준 지시자에 대한 이해를 제대로 하고 있는지 확인하기 위해서 몇가지 코드를 작성하며 제대로 이론을 알고 있는지 확인해보기로..

 

첫번째.

→ 당연히 메인 메소드에서 h.print()를 호출할 수 없다.

     (Circle과 Main 클래스가 다른 패키지일 뿐만 아니라 상속관계도 아니기 때문)

 

 

두번째.

→ 첫번째 코드와 비슷하지만, Hello2 클래스에서 Circle 클래스의 print 메소드를 호출했다.

     (super 키워드를 통해 부모클래스에 접근)

→ 메인 메소드에서는 print 메소드에 접근하는 것을 지웠다.

 

→ 당연히 문제 없이 결과가 출력됐다.

→ Hello2에서 Circle의 print 메소드에 접근할 수 있는 이유는 다른 패키지로 묶여있지만 상속관계이고 protected이기 때문

→ 참고로 메인 메소드에서 Hello2의 printHello 메소드가 (protected임에도 불구하고) 호출될 수 있는 이유는 "같은 패키지 내" 이기 때문이다.

 

여기까지 내가 알고 있는 protected 개념을 이용해서 알고 있는 이론을 정리했다.

 

이제 처음에 궁금증을 품었던 상황과 비슷하게 코드를 만들어서 하나씩 확인해보기로 했다.


 

궁금하다고 했던 코드의 상황을 그림으로 정리하면 아래와 같다.

 

이와 비슷한 상황을 예시 코드들로 만들어보고, 세가지 정도 테스트해보기로 했다.

 

#준비사항. Main과 Hello2 모두 Circle 클래스를 상속하도록 하기

→ 준비됐다.

→ 참고로 Hello2와 Main 클래스는 디폴트 패키지에 있고 Circle은 com.example2.aaa 패키지에 있다.

 

#1. Main 인스턴스에서 Circle 인스턴스를 만들고 print 메소드에 접근해보기

→ print 메소드가 보이지 않는다는 에러가 발생했다.

→ 이 상황에서 Circle 인스턴스를 만들지 않고 super 키워드를 사용한다면?

→ super 키워드는 static 메소드에서 사용할 수 없다고 한다.

 

아, main 메소드(클래스 메소드임)에서는 Main 클래스가 Circle 클래스를 상속 받은 것과 관계없이 super 키워드를 사용할 수 없나보다.

 

그리고, 생각해보니 static 메소드(클래스 메소드)는 인스턴스를 생성하지 않는다고 했다.

코드상으로는 Main 클래스에 소속된 것처럼 보이지만 실제로는 클래스에 소속되어 있지 않고 메모리도 독립적으로 존재한다고 했다.

즉, main 메소드(클래스 메소드)는 '상속 관계'나 '동일 패키지에 속한다' 등의 개념을 떠나 생각해야 하는 듯 하다.

 

그렇다면 메인 메소드에서 protected로 선언된 print 메소드에 접근하지 못하는게 당연한 것이 아닐까.

애초에 메모리 공간도 서로 다른 곳에 있는데 protected 메소드에 접근 가능한 것도 이상한 일이 아닐까 싶다.

 

 

#2. Hello2에서 Circle 인스턴스를 만드고 print 메소드에 접근

→ Hello2 클래스에서 Circle 인스턴스를 만들고 print 메소드에 접근했더니 역시나 에러가 발생했다.

→ 그럼 여기에서 문제가 되는 코드만 수정해서 출력을 성공해보자.

→ super 키워드를 사용해서 부모클래스의 print 메소드에 접근하면 정상적으로 출력되는 것 같다.

→ 그렇다면 내가 이해하지 못하고 있는 부분(확실하게 모르고 있는 개념)은 "protected" 접근수준지시자와 "super"의 관계에 대한 것인 듯 하다.

 

→ 일단 위에서 여러가지 코드를 작성해보며 유추하기로는,

protected 접근수준 지시자의 설명 중 "(다른 패키지에 있어도) 상속관계이면 접근 가능"이라는 것은 "(다른 패키지에 있어도) 상속관계이면 (super 나 this 키워드를 통해서) 접근 가능"하다는 이야기였던 듯 하다.

→ 아마도 자식 클래스에서 부모 클래스의 인스턴스를 하나 생성한 후, protected 접근 수준의 메소드에 접근하는건 "외부"에서 접근하는 것과 동일하게 보는 것이 아닐까.

 

정확하게 확인하기 위해서 protected와 super의 관계에 대해 구글에 검색해보기로 했다.

그리고 그 해답을 찾아왔다.

 

https://stackoverflow.com/questions/47800155/is-protected-method-in-super-class-visible-in-sub-class-in-a-different-package

 

Is protected method in super class visible in sub class in a different package?

It seems very silly, but I am really confused. Please see below code: package com.one; public class SuperClass { protected void fun() { System.out.println("base fun"); } } ---- pac...

stackoverflow.com

 

대충 해석해보자면,

protected 메소드는 자식클래스의 안에서만 볼 수 있고,

만약 새로운 부모클래스의 인스턴스를 생성하면, 그건 자식 클래스의 외부에서 접근하는 것이기 때문에 protected 메소드에 접근이 안된다.

결론적으로 부모 클래스의 protected 메소드에 접근하고 싶으면 자식 클래스 내부에서 this 키워드를 사용하거나 그냥 메소드명만 적어서 접근하라고 말해주었다.

 

 

#3. Main 클래스에서 Hello2 인스턴스 만들고 Circle의 print에 접근 

#3도 당연히 #1과 #2의 이유로 안될 것이다.

 

 

겸사겸사.. 부모클래스의 멤버 변수나 메소드에 접근할 때 대부분 super 키워드가 아니라 this 키워드를 사용한다는 것을 알게 되었다.

(그 둘의 차이에 대한 것은 나중에 찾아보기로 하자)

 


이렇게 하면, 처음에 이해가 가지 않는다고 했던 부분도 해결이 된다.

 

이 코드에서 clone 메소드가 보이지 않는다고 에러가 발생했던 가장 큰 이유를 추측해보면 아래와 같다.

 

"main 메소드는 static 메소드이며, 메모리 공간도 인스턴스와 별개로 존재한다.

clone 메소드 입장에서 main 메소드는 외부에 있는 것이며 상속 관계도 아니기 때문에 protected 메소드에 접근이 불가능한 것" 인 듯 하다.

 

→ Main과 Fish는 모두 Object와 상속 관계이고

→ protected 메소드는 "(다른 패키지에 있어도) 상속 관계이면 접근 가능"이라고 했으니 생각해보면 Main 클래스에서 clone 메소드에 접근 가능할 것 같지만

→ 주목할 점은 Main 클래스가 아니라 static 메소드로 정의된 main 메소드인 듯 하다.

 

 

# 참고로, main 메소드는 super 혹은 this 키워드를 사용할 수 없다고 한다. #

아마도 super와 this 키워드는 자기자신 혹은 부모 객체를 가리키는 키워드인데 (참조값을 반환함)

main 메소드는 static 메소드이기 때문에 "인스턴스"가 아니고,

애초에 인스턴스가 아니기 때문에 "인스턴스의 참조값"을 반환할 수가 없기 때문인 듯 하다.

 

# (코드상으로 main 메소드가 소속되어 있는) Main 클래스 내부에 다른 메소드를 만들어서

super.clone() 을 호출해보면 에러 없이 컴파일하는데 성공한다 #

protected 메소드를 호출하지 못하는 이유를 Main 클래스에 집중해서 이해할 게 아니라 (static 메소드인) main 메소드에 집중해서 이해해야 하는 것 같다.

 

 

만약 (static 메소드가 아닌) Fish 클래스의 메소드에서 Object 인스턴스를 생성하고 clone 메소드에 접근한다고 해도 호출은 불가능할 것이다.

→ 왜냐하면 자식 클래스 안에서 부모 클래스의 인스턴스를 생성한다는 것은 상속받은 부모 인스턴스를 의미하는 것이 아닌 완전히 다른 객체를 의미하기 때문

→ 그러나 this나 super 키워드를 이용하면 접근 할 수 있다.

→ 하지만 굳이 부모 클래스의 clone 메소드도 살려놓고,

자식 클래스에서도 별도로 classClone 이라는 이름으로 비슷한 기능을 하는 메소드를 정의할 필요없이

Java에는 메소드 오버라이딩(자식 클래스에서 clone 메소드의 동작 방법을 변경/수정해서 부모 객체의 clone 메소드를 가려버림)이 있다. 이를 통해 같은 메소드이름으로 동작 방법만 변경할 수 있다.

 

 

따라서, 위와 같은 이유들 때문에 clone 메소드를 오버라이딩 하는 것 같다.

 


독학의 유일한 슬픔은 "모르는 것을 찾을 때 구글을 이용해야 하지만, 어떻게 검색해야할지 모르겠다"는 점인데..ㅠㅠ

 

개인적으로 모르는 부분이나 궁금한게 생기면 알고 있는 범위에서 하나씩 여러가지를 시도해보고

내가 알고 있는게 무엇이고, 모르는 부분이 무엇인지 확실하게 파악해서 구글에 검색하려고 노력하는 편이다.

 

시간은 좀 오래걸리지만,

궁금한 내용을 그대로 구글에 검색해보면 100% 매칭되는 원하는 해답을 찾기가 좀 힘들기 때문에

스스로 생각해보기에 어떤 부분이 원인인 것 같고, 어떤 개념을 잘 모르고 있는건지 좁혀가면서 검색해야 해답을 찾기 더 수월하기 때문이다.. (이래서 멘토가 필요한건가보다)

 

Comments