static
- Java에서 static은 메모리에 한번 할당되어 프로그램이 종료될 때까지 해제하지 않는 것을 의미한다.

- Class는 Static 영역에 생성된다.
- Static 영역에 할당된 메모리는 모든 객체가 공유하는 메모리라는 장점을 지니지만, Garbage Collector가 관리하지 않으므로, 사용할수록 프로그램 종료시까지 할당된 메모리의 크기가 크다.
- new로 생성한 객체는 Heap영역에 생성된다.
- Heap 영역의 메모리는 Garbage Collector를 통해 수시로 관리 받는다.
Static 변수 특징
- Static 변수는 클래스 변수이다.
- 객체를 생성하지 않고도 Static 자원에 접근이 가능하다.
static 변수(정적 변수)
메모리에 고정적으로 할당되어, 프로그램이 종료될 때 해제되는 변수
public class Persion {
private String name = "gonagi";
public void printName(){
System.out.println(this.name);
}
}- 100명의 Person 객체를 생성하면
gonagi의 값을 가지는 메모리 100개가 생성된다. - static을 사용하여 하나의 메모리를 참조하게 하면 메모리 효율이 높아진다. 또한,
gonagi라는 값이 변하지 않으므로final키워드를 붙여주고, 일반적으로static은 상수의 값을 갖는 경우가 많아public을 붙여준다.
public class Persion {
private static final String name = "gonagi";
public static final String APP_NAME = "MyApp";
public void printName(){
System.out.println(this.name);
}
}- 상수들만 모아서 상수의 변수명을 대문자,
_을 조합하여 이름 짓는다. - 상속을 방지하기 위해
final class로 선언한다.
Static 메소드(정적 메소드)
```java
public class Test {
private String name1 = "gonagi";
private static String name2 = "gonagi";
public static void printMax(int x, int y) {
System.out.println(Math.max(x, y));
}
public static void printName(){
// System.out.println(name1); 불가능한 호출
System.out.println(name2);
}
}- 객체 생성 없이 호출이 가능하며, 객체에서는 호출이 가능하지만 지양하고 있다.
- static 메소드에 접근하기 위한 변수는 반드시 static으로 선언되어야 한다.
name1은 new 연산을 통해 객체가 생성된 후에 메모리가 할당된다.- 하지만 static 메소드는 객체의 생성 없이 접근하는 함수이므로, 할당되지 않은 메모리 영역에 접근하는 것이어서 문제가 발생한다.
import java.text.SimpleDateFormat;
import java.util.Date;
import android.util.Patterns;
public final class CommonUtils {
public static String getCurrentDate() {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyMMdd");
return dateFormat.format(date);
}
public static boolean isEmailValid(String email) {
return Patterns.EMAIL_ADDRESS.matcher(email).matches();
}
}- 상속을 방지하기 위해
final class로 선언하고, 유틸 관련된 함수들을 모아둔다.- 유틸리티 클래스는
static메서드로만 구성되며, 인스턴스를 생성하거나 상속할 필요가 없다. - 공통적으로 사용될 메서드를 제공하는 것이므로 상속할 필요가 없다.
- 유틸리티 클래스는
static 클래스
- 중첩 클래스(nested class)를 사용할 때 사용한다.
-
inner class의 문제점은 외부 참조를 하고, 메모리 누수 현상이 발생하는 것이다.
- inner class를 static으로 만들지 않으면
Inner class may be 'static'경고가 발생한다. - inner class를 생성하면 내부 클래스가 외부의 멤버를 사용하지 않아도, 숨겨잔 외부 참조가 생성된다.
- inner class가 outer class 인스턴스에 대한 참조를 갖고 있기 때문에, Garbage Collection은 outer class의 인스턴스를 수거 대상으로 보지 않아 GC의 대상에서 빠지게 된다.
- inner class, outer class 두 인스턴스가 연결되어 있어 outer class 인스턴스의 메모리를 못 뺀다.
- inner class를 static으로 만들지 않으면
import java.util.ArrayList;
class Outer_Class {
// 외부 클래스 배열 변수
private int[] data;
// 내부 클래스
class Inner_Class {
}
// 외부 클래스 Constructor
public Outer_Class(int size) {
data = new int[size]; // 사이즈를 받아 배열 필드의 크기를 불림
}
// 내부 클래스 객체를 생성하여 반환하는 메소드
Inner_Class getInnerObject() {
return new Inner_Class();
}
}
public class Main {
public static void main(String[] args) {
ArrayList<Object> arr = new ArrayList<>();
for (int cnt = 0; cnt < 50; cnt++) {
// inner_Class 객체를 생성하기 위해 Outer_Class를 초기화하고 메서드를 호출하여 리스트에 넣는다.
// Outer_Class 는 메서드 호출용으로 한번 사용되고 더이상 사용되지 않기에 GC 대상이 되어야 한다.
arr.add(new Outer_Class(100000000).getInnerObject());
System.out.println(cnt);
}
}
}Inner_Class을 담을 리스트 arr 생성- 반복문을 통해 50개의
Inner_Class객체를 리스트에 담는다. - 이 떄 내부 클래스 생성을 위해 외부 클래스를 먼저 인스턴스화 해야 하므로,
Outer_Class를 new 키워드로 인스턴스화 한다. Outer_Class생성자 파라미터로 100,000,000 크기의 int 배열이 생성되어 400MB 크기의 객체가 힙 메모리에 쌓인다.- 그리고
getInnerObject()메서드를 호출하여Inner_Class객체를 생성하고 반환한다. - 생성된
Inner_Class객체를 리스트에 저장한다. - 메서드 호출용도로 사용된
Outer_Class는 더이상 필요가 없어 GC 대상이 되어야 하지만,Inner_Class와 결합되어 있어 GC가 관리하지 못한다.
// 내부 클래스
static class Inner_Class {
}- Inner_Class를 static 클래스로 바꾸면, 외부 클래스의 인스턴스와 참조 관계가 없으므로,
Outer_Class가 사용되지 않을 때 GC로 메모리 해제를 할 수 있다.
망나니 개발자 (2019.04) static 변수와 static 메소드 devdo (2022.10) static 변수, static 메서드 그리고 static 클래스 Redddy (2023.08) static 메서드와 static 클래스