class Foo {
public static String classVar = "I Class Var";
public String instanceVar = "I instance Var";
public static void classMethod() {
System.out.println(classVar);
}
public void instanceMethod() {
System.out.println(classVar);
System.out.println(instanceVar);
}
}
public class StaticExample {
public static void main(String[] args) {
System.out.println(Foo.classVar);
Foo.classMethod();
Foo f1 = new Foo();
Foo f2 = new Foo();
System.out.println(f1.classVar);
System.out.println(f1.instanceVar);
f1.classVar = "changed by f1";
System.out.println(Foo.classVar);
System.out.println(f2.classVar);
f1.instanceVar = "changed by f1";
System.out.println(f1.instanceVar);
System.out.println(f2.instanceVar);
}
}
static 메모리
- ✋우리가 만든 Class 👉 Static 영역에 생성된다
- Static 영역은 모든 객체가 공유하는 메모리이고,
GC의 관리 영역 밖에 존재하기때문에 프로그램 종료시까지 메모리가 할당된 채로 존재한다
- JDK 8부터 힙 영역이 기존에 New / Survive / Old / Perm / Native 에서 New / Survive / Old / Metaspace 로 변경 되었다.
- ✋Java7 까지의 Permanent에 Static Object가 존재했지만
👉 Java8 에서의 Metaspace과 Heap 분리되면서
Static Object
와 상수화된 String Obejct
는
Heap 영역으로 이동하게 되었다
- static 변수, 메소드를 남용하면 시스템 성능에 영향을 준다
- ✋new 연산으로 만든 Instance 👉 Heap 영역에 생성된다
- Heap 영역은 GC를 통해 수시로 관리 받는다.
static 변수
- 메모리에 고정적으로 할당되어, 프로그램이 종료될 때 해제되는 변수이다
- 해당 클래스 객체를 생성하지 않고도 static 자원에 접근할 수 있다
✅ static 변수
, static 메소드
👉 객체가 생성되기 이전에 이미 static 영역에 할당되므로, 객체 생성 없이 바로 접근할 수 있다.
👉 멤버변수 중에서 모든 인스턴스에 공통적으로 사용해야 하는 것이 있다면 static을 붙인다.
✍예시
public class Person {
private String name = "Hjoon";
public void printName() {
System.out.println(this.name);
}
}
public class Person {
public static final String name = "Hjoon";
public static void printName() {
System.out.println(this.name);
}
}
- person 객체를 여러개 생성하면 "Hjoon"이라는 작은 값을 가지는 메모리가 중복되어 생성된다
- 👉 static을 사용하여 여러 객체가 하나의 메모리를 참조하도록한다 (메모리 효율적)
- 👉 final 키워드를 사용한다 (변하지 않을 값이므로)
- 👉 public으로 선언한다 (변수가 아니라 상수의 값을 가질 경우에만)
public static final String name = "Hjoon"
- static 변수를 사용하는 메소드는 static으로 선언되어야 한다
public static void printName()
✍활용
public final class AppConstants {
public static final String APP_NAME = "MyApp";
public static final String PREF_NAME = "MyPref";
}
- 상수의 변수명은 대문자와 _를 조합하여 이름짓는다
- 상속을 방지하기 위해 final class로 선언을 한다.
static 메소드
- 객체 생성 없이 호출 가능한 메소드이다 👉 객체에서 호출 가능하지만, 지양한다
- 일반적으로 Utility 관련 함수들은 여러번 사용되므로 static 메소드로 구현한다
java.util.Math
라는 Util Class
public class StaticExample {
private String name1 = "Hjoon";
private static String name2 = "Hjoon";
public static void printMax(int x, int y) {
System.out.println(Math.max(x, y));
}
public static void printName(){
System.out.println(name2);
}
}
- static 메소드
public static void printMax(int x, int y)
- static 메소드로 선언된 Math 클래스의
max
함수를 초기화 없이 사용한다
- static 메소드
public static void printName()
- 👉
name2
: 객체가 생성되기 이전에 메모리가 Static 영역에 할당된다
- 👉
name1
: new 연산으로 객체가 생성된 후 메모리가 Heap 영역에 할당된다
- static 으로 선언되지 않은 변수는 아직 메모리가 할당되지 않으므로 접근 불가능
✍활용
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이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용할 수 있다.
- static이 붙은 메서드(함수)에서는 인스턴스 변수를 사용할 수 없다.
- 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.
- 작성한 메서드 중에서 인스턴스 변수를 사용하지 않는 메서드에 대해서 static을 붙일 것을 고려한다