static

khs·2022년 9월 3일
0

자바

목록 보기
1/3

정적(Static)이란?

정적(static)은 고정된이란 의미를 가지고 있으며 Java에서 Static 키워드를 사용한다는 것은 메모리에 한번 할당되어 프로그램이 종료될 때 해제되는 것을 의미한다. 이를 정확히 이해하기 위해서는 메모리 영역에 대한 이해가 필요하다.

Static이라는 키워드를 사용하여 Static변수와 Static메소드를 만들 수 있는데 다른말로 정적필드와 정적 메소드라고도 하며 이 둘을 합쳐 정적 멤버라고 한다. (클래스 멤버라고도 한다.) 정적 필드와 정적 메소드는 객체(인스턴스)에 소속된 멤버가 아니라 클래스에 고정된 멤버이기 때문에 클래스 로더가 클래스를 로딩해서 메소드 메모리 영역에 적재할때 클래스별로 관리된다. 따라서 클래스의 로딩이 끝나는 즉시 바로 사용할 수 있다.

일반적으로 우리가 만든 Class는 Static 영역에 생성되고, new 연산을 통해 생성한 객체는 Heap영역에 생성된다. 객체의 생성시에 할당된 Heap영역의 메모리는 Garbage Collector를 통해 수시로 관리를 받는다. 반면 Static 키워드를 통해 Static 영역에 할당된 메모리는 모든 객체가 공유하는 메모리라는 장점을 지니지만, Garbage Collector의 관리 영역 밖에 존재하므로 Static을 자주 사용하면 프로그램의 종료시까지 메모리가 할당된 채로 존재하므로 자주 사용하게 되면 시스템의 퍼포먼스에 악영향을 주게 된다.


static 변수

Java에서 Static 변수는 메모리에 한번 할당되어 프로그램이 종료될 때 해제되는 변수로 메모리에 한번 할당되므로 여러 객체가 해당 메모리를 공유하게 된다.


public class Number {
	public static final int num1 = 0;
	int num2 = 0;
}

public class Main {  
	public static void main(String[] args) {
		Number number1 = new Number();
		Number number2 = new Number();
		
		number1.num1++;
		number1.num2++;
		
		System.out.println(number2.num1);  // number2의 클래스 필드 출력 1
		System.out.println(number2.num2);  // number2의 클래스 필드 출력 0
	}
}

Number이라는 클래스안에 클래스 변수 num1과 인스턴스 변수 num2를 생성하였고 두 개의 Number인스턴스 number1과 number2를 생성하였다. number1에서 num1과 num2를 각각 1씩 증가시키고 number2에서 num1와 num2를 각각 출력시켰을때는 num1은 1, num2는 0이 출력되었다.

왜 이런 현상이 나타났느냐면 인스턴스 변수는 인스턴스가 생성될 때마다 생성되므로 인스턴스마다 각기 다른 값을 가지지만 정적 변수는 모든 인스턴스가 하나의 저장공간을 공유하기에 항상 같은 값을 가지기에 나타난 현상이다.

일반적으로 Static은 상수의 값을 갖는 경우가 많으므로 public으로 선언을 하여 사용한다. 이러한 이유로, 일반적으로 static 변수는 public 및 final과 함께 사용되어 public static final로 활용되며 static 변수는 static 메소드를 통해 접근하도록 권장된다.


static 메소드

정적 메소드는 클래스가 메모리에 올라갈 때 정적 메소드가 자동적으로 생성된다. 그렇기에 정적 메소드는 인스턴스를 생성하지 않아도 호출을 할 수 있다.

class Name{
    static void print() { //클래스 메소드
	System.out.println("내 이름은 홍길동입니다.");
    }

    void print2() { //인스턴스 메소드
	System.out.println("내 이름은 이순신입니다.");
    }
}

public class Static_ex {
	
    public static void main(String[] args) {
        Name.print(); //인스턴스를 생성하지 않아도 호출이 가능
    	
        Name name = new Name(); //인스턴스 생성
        name.print2(); //인스턴스를 생성하여야만 호출이 가능
    }
}

Static Method는 객체의 생성 없이 호출이 가능하며, 객체에서는 호출이 불가능하다. (static 변수에 접근하기 위한 메소드는 반드시 static 메소드가 되어야 한다.) 일반적으로는 유틸리티 관련 함수들은 여러 번 사용되므로 static 메소드로 구현을 하는 것이 적합한데, static 메소드를 사용하는 대표적인 Util Class로는 java.uitl.Math가 있다.


싱글톤 패턴

static에 대한 개념이 생겼기 때문에 싱글톤을 이해하는것이 어렵지 않다. 싱글톤은 단 하나의 객체만을 생성하게 강제하는 패턴이다. 즉 클래스를 통해 생성할 수 있는 객체는 한 개만 되도록 만드는 것이 싱글톤이다. 아래 예제를 확인해보자.

public class Printer {
	private static Printer printer = null; //Printer 클래스 내에 Printer static 변수 생성
	private Printer() {};  //생성자를 private로 선언하여 객체 생성을 불가능하게 함
	
	public static Printer getInstance() {
		if(printer == null) {
			printer = new Printer();
		}
		return printer;
	}
	
	public void print(String input) {
		System.out.println(input);
	}
}

public class Main {  
	public static void main(String[] args) {
		Printer p1 = Printer.getInstance();
		Printer p2 = Printer.getInstance();
		
		p1.print("hi");
		p2.print("hello");
	}
}

getInstance는 내부적으로 생성되지 않았다면 생성하고, 기존에 생성된 값이 존재한다면 생성된 인스턴스를 리턴하는 형태로 프로그램 전반에 걸쳐 하나의 인스턴스를 유지한다. 또한 참고할 점은 인스턴스를 제공하는 메서드와 인스턴스 변수 모두 Static으로 선언된 정적 변수 및 메서드이다. 당연히 기본생성자를 통해 생성할 수 없기 때문에, 외부에서 인스턴스에 접근하려면 클래스 변수 및 메서드에 접근을 허용해야하기 때문에 두 메서드는 정적타입으로 선언되어 있다.

위와 같은 코드에는 Multi-Thread 환경에서 안전하지 않기 때문에 문제점이 있다. 여러 쓰레드가 공유되고 있는 상황에서는 하나의 인스턴스가 아닌 여러개의 인스턴스가 발생 할 위험이 있다. 또한 그 값이 일관되지 않을 수 있다.

※ 쓰레드 환경에서도 안전한 싱글톤을 만드는 방법은 이곳에 어울리지 않으므로 생략한다.

profile
권혁상입니다. 행복코딩^_^

0개의 댓글