Static
Java에서 Static을 사용하는 대부분의 이유는 메모리에 한번 할당해 프로그램이 종료될 때까지 사용하고 종료될 때 메모리에서 사라지게 하기 위해 사용할 텐데요. 메모리를 중요시하여 사용하는 만큼 당연히 메모리 영역에 대해 이해도가 어느정도 있어야 될 것입니다.
우리가 만든 Class는 메모리에 올라갈 때 Static 영역(메서드 영역)에 생성되고, new 연산자를 통해서 생성한 객체는 Heap 영역에 생성이 됩니다. 또한 Heap 영역에 생성된 객체들은 GC(Garbage Collector)를 통하여 관리를 받습니다. 하지만 Static를 사용하여 Static 영역(메서드 영역)에 할당된 메모리는 장점으로써는 모든 객체가 공유하는 메모리라는 것이 있지만 단점으로는 GC에 관리 대상이 되지 않기 때문에 Static을 자주 사용하거나 무분별하게 사용하게 되면 애플리케이션의 성능 또한 문제가 생길 겁니다.
Static의 장점
첫째는 메모리를 효율적으로 사용이 가능합니다. 예시를 들자면 자주 사용하는 객체를 사용할 때마다 매번 Heap 영역에 올려 사용한다면 정말 애플리케이션 성능에 좋지 않을 것입니다. 그리하여 Static 키워드를 사용하여 메서드 영역에 올려 고정적으로 메모리에 적재시킨다면 Heap 영역에 올려 사용하는 것보다 매우 효율적일 것 입니다.
둘째로는 속도가 있습니다. 우리는 Static을 사용하여 new 연산자를 사용하여 객체를 생성한 것이 아니기 때문에 속도가 빠르다는 장점이 존재합니다.
Static의 단점
장점이 존재하면 단점도 물론 존재할 것입니다.
첫째는 메모리 누수(Leak)이다. Static은 정적으로 메서드 영역에 적재되어 애플리케이션이 종료되기 전까지 메모리에서 사라지지 않다. 또한, GC에 대상이 아니라는 점에서 무분별한 Static의 사용은 메모리 누수의 원인이 될 수 있다.
둘째는 재사용성의 문제이다. Static은 알다시피 정적인 존재이기 때문에 동적으로 바뀔 수 없어
interface의 구현대상에 적합하지 않는다.
Instance
Static에 대해 말했으니 그의 반대인 인스턴스도 간단하게 한번 말해보면 좋을 것 같다. 인스턴스는 static과 다르게 Heap 영역으로 가는 친구이다. 인스턴스는 GC의 대상이 되기 때문에 수시로 관리를 받는다.
장점으로는 인스턴스는 동적이기 때문에 재사용성이 좋고 필요에 따라서 여러 개의 인스턴스를 생성할 수 있다.
단점으로는 필요에 따라 여러 개의 인스턴스를 생성하는 만큼 리소스를 그만큼 잡아먹는다. 인스턴스는 생성할 때마다 new로 생성해야 되기 때문에 그만큼의 리소스를 잡아먹는 것은 당연하다.
Static의 특징
Static의 변수는 클래스의 변수이기 때문에 객체를 생성하지 않아도 접근이 가능하다.
public class Main {
public static String name = "jiseong";
public static void print() {
System.out.println(name);
}
public void print1() {
System.out.println(name);
}
public static void main(String[] args) {
Main.print();
Main.print1();
Main main = new Main();
main.print();
main.print1();
}
}
정적 변수
자바에서 정적 변수는 메모리에 한번 할당되면 애플리케이션이 종료될 때 내려가는 변수로, 메모리에 한번 할당되므로 여러 개의 객체가 해당 메모리를 공유하게 된다.
public class Main {
public String name = "jiseong";
public void print() {
System.out.println(name);
}
}
위에 있던 코드의 일부를 수정하였습니다. 만약에 print()를 100명 또는 1000명이 호출하게 되면 어떤 일이 일어날까요?
예상하는 대로 100개 또는 1000개의 인스턴스가 생성되어 매우 좋지 않은 상황이 일어날 수도 있을 겁니다.
그래서 이것을 한번 수정해 보면 좋을 것 같습니다. 이런 경우에는 static을 사용하여 여러 객체가 하나의 메모리 즉 name을 참조하도록 하면 메모리 효율이나 애플리케이션 측면에서도 좋은 방향일 것 같습니다.
또한 name은 변하지 않을 값이니 불변의 값이라는 final을 같이 사용해 주면 좋을 것 같습니다.
public class Main {
public static final String name = "jiseong";
public static void print() {
System.out.println(name);
}
}
위에 처럼 수정해 준다면 100명이든 1000명이든 모두가 같은 메모리를 참조하여 불필요한 인스턴스가 생성되지 않고 메모리 측면에서도 매우 좋을 것 같다.
정적 메서드
정적 메서드란 객체를 생성하지 않고 "Main.print()"와 같은 방식이다. 이 방식을 사용한다면 클래스 내에 존재하는 인스턴스 변수를 사용할 수 없다.
class Math1 {
int a,b;
int add(){
return a + b;
}
static int add(int a, int b){
return a + b;
}
}
class Main {
public static void main(String args[]) {
System.out.println(Math1.add(200,100);
Math1 mt1 = new Math1();
mt1.a = 200;
mt1.b = 100;
System.out.println(mt1.add());
}
}
정리
static은 무분별하게 사용하는 것이 아닌 정적인 값과 같은 상황에 사용하면 유용한 것이다. 정적 변수와 정적 메서드의 예시를 보면서 감이 어느 정도 잡혔겠지만 한 가지 의문점을 제시하자면 "static 메서드는 왜 인스턴스 변수를 호출하지 못할까?"라는 의문이 들 수 있다. 이것에 대해 이야기해 보면 static은 말했듯이 객체를 생성하여 인스턴스가 아닌 정적인 존재이다. 하지만 무조건 안된다라는 말이 아니라 인스턴스 객체의 생성 여부에 따라 호출이 되냐 안되냐가 갈라지는 것이다. 클래의 인스턴스 객체를 생성하지도 않은 상태에서 인스턴스 변수를 호출하면 에러가 나는 것은 당연하다. 그래서 이런 점을 유의해서 올바른 코드를 짜면 좋을 듯하다.