static class 와 static method 차이
`static class` 는 inner class 에서 사용되는 개념으로 Outer class 를 인스턴스화 없이 사용하는 클래스를 (inner) static class 라고 합니다. 그리고 `static method` 또한 속한 클래스의 인스턴스화 없이 사용되는 메소드를 의미합니다.
예시를 보면 이해가 더 쉽습니다.
class Outer {
class NonStaticInner { }
static class StaticInner { }
public static void print() { }
}
Outer.NonStaticInner = new Outer.NonStaticInner(); // 컴파일 에러
Outer.StaticInner instance = new Outer.StaticInner();
Outer.print();
그렇다면 여기서 `static` 은 어떠한 의미를 갖는지 궁금했는데요. 찾아보니 외부 클래스와 상관없이 `독립적`으로 `고정된` 클래스/메소드라는 뜻인거 같네요.
Inner class 는 꼭 static 선언을 해야한다
nested class에 대한 이야기 때문에 static inner class를 접하게 됩니다. Inner 클래스는 꼭 static 으로 선언을 해야하는 이유는 외부참조를 하지 않기 위함입니다. 예를 들어, Inner 클래스를 인스턴스화하는 과정 속에서 Outer 클래스도 같이 인스턴스화를 했습니다. Outer 클래스가 더 이상 필요없어서 가비지 컬렉션이 되길 원했지만 해당 코드는 OOM 에러가 발생합니다.
public class Main {
public static void main(String[] args) {
int maxSize = 100_000_000;
List<Outer.NonStaticInner> nonStaticInners = new ArrayList<>();
int round = 1000;
for(int i = 0; i < round; i++) {
nonStaticInners.add(new Outer(new int[maxSize]).new NonStaticInner(new int[1]));
}
System.out.println("end");
}
}
class Outer {
int[] oarray;
Outer(int[] oarray) {
this.oarray = oarray;
}
class NonStaticInner {
int[] nsi;
NonStaticInner(int[] nsi) {
this.nsi = nsi;
}
}
static class StaticInner {
int[] si;
StaticInner(int[] si) {
this.si = si;
}
}
}
이유는 static 없는 Inner 클래스의 생성자를 디컴파일하면 알 수 있습니다. 알고보니 Outer 클래스에 대한 참조를 갖고 있었습니다. 그래서 Inner->Outer 참조를 갖고 있기 때문에 Outer가 GC되지 않고 OOM이 발생한겁니다.
class NonStaticInner {
int[] nsi;
// decompile 하면 외부 클래스였던 Outer 에 대한 참조가 생긴다
NonStaticInner(final Outer this$0, int[] nsi) {
this.nsi = nsi;
}
public void helloNonStaticInner() {
System.out.println("hello non static inner");
}
}
그렇기 때문에 Inner 클래스는 외부에 대한 참조를 갖지 않으면 static으로 선언해서 `외부 클래스와 상관 없이 독립적으로 고정된` 상태로 선언을 해야합니다.
public class Main {
public static void main(String[] args) {
int maxSize = 100_000_000;
List<Outer.StaticInner> staticInners = new ArrayList<>();
int round = 1000;
for(int i = 0; i < round; i++) {
staticInners.add(new Outer.StaticInner(new int[1]));
}
System.out.println("end");
}
}
class Outer {
int[] oarray;
Outer(int[] oarray) {
this.oarray = oarray;
}
static class StaticInner {
int[] si;
StaticInner(int[] si) {
this.si = si;
}
}
}
클래스 안에 존재하는 enum은 static 선언을 해줘야할까요?
inner 클래스는 static 를 선언해야 하는데 enum도 static 선언을 해줘야 하는지에 대해 공식 문서에 언급된 내용이 있습니다. 원래도 암묵적으로 static이기 때문에 굳이 다시 붙일 이유는 없다고 하네요.
마무리
static 이 어떠한 의미인지 알아보는 시간을 보냈습니다. 결국엔 외부 클래스 인스턴스화 없이 `독립된` 상태가 핵심인거 같네요!
'📗Java' 카테고리의 다른 글
[Java] Virtual Thread 알아보기 (0) | 2024.05.23 |
---|---|
[Java] Arrays.sort() 어떤 정렬 알고리즘을 쓸까? (2) | 2024.04.30 |
[모던자바인액션] Optional (0) | 2023.10.23 |
[Java] Reflection API (5) | 2023.09.24 |
[모던자바인액션] 람다 표현식 (1) | 2023.09.14 |