아침에 일어나 보니 제가 들어가 있는 '개발바닥'이라는 오픈카톡방에서 어떤 한 분이 다음과 같은 글을 올리셨습니다.
혹시 상속관계에서 왜 static 메서드는 오버라이딩이 되지 않는지 정확히 아시는 분 계신가요,,
제가 JVM구조를 보면서 공부한 바로는 static은 Method Area에 저장이 되고, 객체는 Heap 영역에 저장이 됩니다.
그렇다면 부모에서 정의한 static 메서드(자식에게도 같은 이름의 static 메서드 정의함)는 객체가 생성되기 전에 Method Area에 들어가는거겠죠?
이제 자식 객체를 생성하고 static 메서드를 호출하면 부모의 method가 나오게 됩니다 이건 오버라이딩이 아니라 hiding이라고 하는 것까지 알고 있습니다.
그렇다면 자식이 같은 static 메서드를 호출할 때 method area에 있는 메서드가 우선순위에 있다라는 걸까요??
저는 hiding이 뭔지도 몰랐는데.. 참 여러모로 톡방은 많은 도움이 되는 거 같습니다..
그래서 이 질문부터 이해해 보려고 JVM 메모리 구조와 자바 메모리 관리 방법도 공부했습니다... ㅎ
네 그래서 이번 포스팅은, 위 질문인 주제인 Hiding에 대해서 다루려 합니다.
Hiding은 쉽게 말하면 static 메서드를 Overridie 하는 것인데요, 따라서 static에 대해 먼저 이해하고 Hiding을 공부해 보도록 하겠습니다.
static?
공부하실 때 아마 '정적인' 이라는 의미로들 공부하셨을 거 같습니다.
정적 멤버(혹은 클래스 멤버)인 static field(정적 필드)와 static method(정적 메서드)를 만드는 데 사용합니다.
인스턴스의 멤버가 아닌 클래스에 고정된 멤버이기 때문에, '고정된', '정적인' 이라는 뜻의 static을 사용하지 않았을까 하는 생각이 듭니다.
자원들을 사용하기 위해서는 메모리를 할당받아야 하고, Java에서는 다음 두 가지 방법으로 메모리를 할당받을 수 있습니다.
- 객체 생성
- static 사용
(여기부터는 아래 링크에서 소개하는 자바의 메모리 관리와, JVM 메모리 구조를 보고 오시면 이해하시기 편할 것입니다.)
https://ttl-blog.tistory.com/368
https://ttl-blog.tistory.com/369
객체는 생성되면 Heap 영역에 저장되고, 해당 객체에 대한 참조값은 Stack 영역에 저장됩니다.
그런데 Class Loader가 .class 파일을 탐색하던 중, static 키워드를 발견하는 순간, 해당 멤버는 Method Area에 메모리가 할당됩니다.
Method Area는 모든 스레드에서 공유하는 영역이므로, 하나의 멤버를 모든 스레드에서 참조할 수 있습니다.
그러나 GC(가비지 컬렉터)의 관리 영역이 아니기 때문에 Method Area에 있는 멤버들은 프로그램의 종료시까지 메모리가 할당된 채로 존재하게 됩니다.
추가로 자바 8부터는 static이 붙은 object(primitive type 제외)는 Heap 영역에서 관리하게 됩니다..!
https://openjdk.java.net/jeps/122
https://jgrammer.tistory.com/144
Hiding
주제인 Hiding이 드디어 등장했습니다.
우선 기본적으로는 static 메서드는 Override가 불가능하다는 것을 알고 있으실 거라 믿습니다.
오버라이딩은 런타임 시점에 발생합니다. static은 컴파일 시점에 이미 Method Area Heap Area에 할당되기 때문에 오버라이딩이 발생할 수 없습니다.
Hiding은 이름 그대로 숨기는 것 입니다.
부모 클래스의 정적 메서드를 자식 클래스에서 똑같이 정의함으로써 부모 클래스의 정적 메서드가 숨겨집니다.
사용 예시를 보면 이해가 쉬울 것 같습니다.
public class Test {
public static void main(String args[]) {
A a = new B();
B b = new B();
a.classMethod(); // classMethod() in A 가 출력된다.
a.instanceMethod(); // instanceMethod() in B 가 출력된다.
((B) a).classMethod(); // classMethod() in B 가 출력된다.
b.classMethod(); // classMethod() in B 가 출력된다.
((A) b).classMethod();// classMethod() in A 가 출력된다.
A.classMethod(); // classMethod() in A 가 출력된다.
}
}
class A {
public static void classMethod() {
System.out.println("classMethod() in A");
}
public void instanceMethod() {
System.out.println("instanceMethod() in A");
}
}
class B extends A {
public static void classMethod() {
System.out.println("classMethod() in B");
}
public void instanceMethod() {
System.out.println("instanceMethod() in B");
}
}
네 참.. 오는 길은 험난했지만.. Hiding은 사실 별거 없었네요
📔 Reference
'☕️ Java > 기본' 카테고리의 다른 글
[Java] String = "" 과 new String("")의 차이 (0) | 2022.01.28 |
---|---|
[Java] final 키워드 (상수와 리터럴) (0) | 2022.01.28 |
자바는 어떻게 작동하는가? (JVM, Class Loader, JVM Memory 등) (0) | 2022.01.24 |
[Java] 자바 JVM 메모리 관리 파헤치기 (스택, 힙, Reference Type, 가비지 컬렉터) (0) | 2022.01.24 |
[Java] ThreadLocal에 대해 (0) | 2022.01.22 |