자바 : 정적 초기화 블록은 언제 유용합니까?


91

static블록 내 초기화의 차이점은 무엇입니까?

public class staticTest {

    static String s;
    static int n;
    static double d;

    static {
        s = "I'm static";
        n = 500;
        d = 4000.0001;
    }
    ...

그리고 개별 정적 초기화 :

public class staticTest {

    static String s = "I'm static";
    static int n    = 500;
    static double d = 4000.0001;

    ....

1
정적 초기화 블록에서만 할당을 사용하므로 물론 정적 변수 할당을 사용하여 수행 할 수 있습니다. 비 할당 문을 실행해야하는 경우 어떤 일이 발생하는지 확인해 보셨습니까?
Platinum Azure

클래스를로드하거나 네이티브 라이브러리를로드하기에 좋은 곳입니다.
qrtt1

1
정적 변수는 피해야하므로 정적 초기화 블록은 일반적으로 좋은 생각이 아닙니다. 그것들을 많이 사용하고 있다면, 몇 가지 문제를 예상하십시오.
Bill K

답변:


106

정적 초기화 블록은 예를 들어 조건문을 사용하여 더 복잡한 초기화를 허용합니다.

static double a;
static {
    if (SomeCondition) {
      a = 0;
    } else {
      a = 1;
    }
}

또는 단순한 구성 이상이 필요한 경우 : 빌더를 사용하여 인스턴스를 생성 할 때 예외 처리 또는 정적 필드 생성 이외의 작업이 필요합니다.

정적 초기화 블록은 인라인 정적 이니셜 라이저 이후에도 실행되므로 다음이 유효합니다.

static double a;
static double b = 1;

static {
    a = b * 4; // Evaluates to 4
}

3
"b = a * 4;" 인라인은 b가 a 이전에 선언 된 경우에만 문제가되며, 이는 귀하의 예에서는 그렇지 않습니다.
George Hawkins

1
@GeorgeHawkins 나는 정적 이니셜 라이저가 인라인 이니셜 라이저 이후에 실행된다는 것을 보여 주려고 노력하고 있었으며 동등한 것이 인라인으로 수행 될 수 없다는 것이 아닙니다. 그러나 나는 귀하의 요점을 취하고 더 명확하게 예제를 업데이트했습니다.
Rich O'Kelly 2012

1
재미를 위해 첫 번째 예제가 "static double a = someCondition? 0 : 1;"처럼 쉽게 될 수 있음을 지적 할 수 있습니다. 아니 당신의 예는 큰 아니라는 것을, 난 그냥 말인지 ... :)
빌 K

18

일반적인 사용법 :

private final static Set<String> SET = new HashSet<String>();

static {
    SET.add("value1");
    SET.add("value2");
    SET.add("value3");
}

정적 이니셜 라이저없이 어떻게할까요?


2
답변 : Guava :) +1
Paul Bellora 2012

2
추가 라이브러리가없는 또 다른 대답 : 초기화를 캡슐화하는 정적 메서드를 만들고 SET변수 이니셜 라이저 ( private final static Set<String> SET = createValueSet())를 사용합니다 . 5 세트와 2 개의 맵이 있다면 모두 하나의 static블록에 버리 겠습니까?
TWiStErRob

14

static{}아래와 같이 try / catch 블록을 사용할 수 있습니다 .

MyCode{

    static Scanner input = new Scanner(System.in);
    static boolean flag = true;
    static int B = input.nextInt();
    static int H = input.nextInt();

    static{
        try{
            if(B <= 0 || H <= 0){
                flag = false;
                throw new Exception("Breadth and height must be positive");
            }
        }catch(Exception e){
            System.out.println(e);
        }

    }
}

추신 : 이것 에서 참조 !


11

초기화 중 예외 처리는 또 다른 이유입니다. 예를 들면 :

static URL url;
static {
    try {
        url = new URL("https://blahblah.com");
    }
    catch (MalformedURLException mue) {
        //log exception or handle otherwise
    }
}

이는 위와 같이 확인 된 예외를 성가 시게 던지는 생성 자나 예외가 발생하기 쉬운 더 복잡한 초기화 로직에 유용합니다.


5

때로는 정적 변수에 값을 할당하는 것 이상을 원할 때가 있습니다. 클래스 본문에 임의의 문을 넣을 수 없기 때문에 정적 초기화 블록을 사용할 수 있습니다.


4

귀하의 예에는 차이가 없습니다. 그러나 종종 초기 값은 단일 표현식에서 편안하게 표현되는 것보다 더 복잡합니다 (예 : List<String>내용이 for루프 로 가장 잘 표현되는 a 이거나 Method존재하지 않을 수 있으므로 예외 처리기가 필요함). 정적 필드는 특정 순서로 설정해야합니다.


4

static블록은 동기화 된 메서드 사용을 방지하기 위해 싱글 톤 인스턴스 를 초기화하는 데 사용할 수 있습니다 . getInstance()


3

기술적으로는 그것 없이도 벗어날 수 있습니다. 일부는 정적 메서드로 이동하기 위해 여러 줄 초기화 코드를 선호합니다. 비교적 간단한 다중 문 초기화를 위해 정적 이니셜 라이저를 사용하는 것이 매우 기쁩니다.

물론 거의 항상 정적을 final만들고 수정할 수없는 개체를 가리 킵니다.


3

정적 키워드 (변수이든 블록이든)는 클래스에 속합니다. 따라서 클래스가 호출되면 이러한 변수 또는 블록이 실행됩니다. 따라서 대부분의 초기화는 static 키워드의 도움으로 수행됩니다. 클래스 자체에 속하므로 클래스의 인스턴스를 만들지 않고도 클래스에 직접 액세스 할 수 있습니다.

예를 들어 봅시다. 색상, 크기, 브랜드 등 여러 변수가있는 신발 클래스가 있습니다. 여기에서 신발 제조업체에 브랜드가 하나만있는 경우 정적 변수로 초기화해야합니다. 따라서 신발 클래스가 호출되고 다른 유형의 신발이 제조 될 때 (클래스의 인스턴스를 생성하여) 새 신발이 생성 될 때마다 색상과 크기가 메모리를 차지하지만 여기서 브랜드는 모든 신발의 공통 속성입니다. 몇 개의 신발을 만들어도 한 번만 메모리를 차지합니다.

예:

    class Shoe {
    int size;
    String colour;
    static String brand = "Nike";

    public Shoe(int size, String colour) {
        super();
        this.size = size;
        this.colour = colour;
    }

    void displayShoe() {
        System.out.printf("%-2d %-8s %s %n",size,colour, brand);
    }

    public static void main(String args[]) {
        Shoe s1 = new Shoe(7, "Blue");
        Shoe s2 = new Shoe(8, "White");

        System.out.println("=================");
        s1.displayShoe();
        s2.displayShoe();
        System.out.println("=================");
    }
}

1

생성자를 사용하여 인스턴스 변수 (비 정적 변수, 클래스가 아닌 객체에 속하는 변수)를 초기화합니다.

클래스 변수 (정적 변수)를 초기화하고 객체를 생성하지 않고 수행하려면 (생성자는 객체 생성시에만 호출 가능) 정적 블록이 필요합니다.

static Scanner input = new Scanner(System.in);
static int widht;
static int height;

static
{
    widht = input.nextInt();
    input.nextLine();
    height = input.nextInt();
    input.close();

    if ((widht < 0) || (height < 0))
    {
        System.out.println("java.lang.Exception: Width and height must be positive");
    }
    else
    {
        System.out.println("widht * height = " + widht * height);
    }
}

정적 초기화 프로그램에서 stdin을 읽는 것은 꽤 끔찍한 생각입니다. 그리고 System.out.println("B * H");꽤 쓸모가 없습니다. 그리고 대답 자체는 매우 모호합니다. OP는 생성자 또는 인스턴스 변수를 언급하지 않았습니다.
shmosel

이것은 정적 이니셜 라이저가 무엇이며 어떻게 사용되는지 보여주는 예제 일뿐입니다. OP는 생성 자나 인스턴스 변수를 요구하지 않았지만 그에게 생성자와 정적 이니셜 라이저의 차이점을 알려주기 위해서는 그것을 알아야합니다. 그렇지 않으면 "내 정적 변수를 초기화하는 데 생성자를 사용하지 않는 이유는 무엇입니까?"라고 말합니다.
Michael

0

정적 코드 블록을 사용하면 instuction 이상으로 필드를 초기화하고 선언의 다른 순서로 필드를 초기화 할 수 있으며 조건부 초기화에도 사용할 수 있습니다.

더 구체적으로,

static final String ab = a+b;
static final String a = "Hello,";
static final String b = ", world";

a와 b가 ab 뒤에 선언되기 때문에 작동하지 않습니다.

그러나 정적 초기화를 사용할 수 있습니다. 이것을 극복하기 위해 블록.

static final String ab;
static final String a;
static final String b;

static {
  b = ", world";
  a = "Hello";
  ab = a + b;
}

static final String ab;
static final String a;
static final String b;

static {
  b = (...) ? ", world" : ", universe";
  a = "Hello";
  ab = a + b;
}

3
당신이 말하는 것은 사실이지만 정적 초기화 블록의 필요성을 보여주지는 않습니다. ab선언을의 선언 아래 로 이동할 수 있습니다 b.
gawi

0

정적 초기화 블록은 클래스를 처음 사용하기 전에 지정된 클래스 정적 유형을 초기화하려는 경우 유용합니다. 후속 사용은 정적 초기화 블록을 호출하지 않습니다. 인스턴스 멤버를 초기화하는 인스턴스 이니셜 라이저의 정반대입니다.


0

클래스 로딩 시간 동안 특정 표현식을 평가하려면 정적 블록을 사용할 수 있지만 다음을 기억하십시오.

정적 블록에서 예외를 처리해야합니다. 즉, 정적 블록에서 예외를 throw 할 수 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.