2012-02-21 2 views
38

В чем разница между инициализации в static блока:Java: Когда полезен статический блок инициализации?

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

Вы используете назначения только в статическом блоке инициализации, так что, конечно, это можно было бы сделать, используя статическое назначение переменных. Пробовали ли вы, что произойдет, если вам нужно выполнить инструкции без присваивания? –

+0

Это хорошее место для загрузки классов или загрузки собственной библиотеки. – qrtt1

+0

Обратите внимание, что статические переменные следует избегать, и поэтому статические блоки инициализации, как правило, не являются отличной идеей. Если вы слишком много используете их, ожидайте, что сработает проблема. –

ответ

48

А статические блоки инициализации позволяет более сложную инициализацию, например, с помощью условных:

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 
} 
+1

Выполнение «b = a * 4;» inline будет проблемой только в том случае, если b был объявлен до a, что не соответствует вашему примеру. –

+1

@GeorgeHawkins Я только пытался проиллюстрировать, что статический инициализатор запускается после встроенных инициализаторов, а не то, что эквивалент не может быть выполнен inline. Тем не менее, я беру вашу точку зрения и обновил пример, чтобы (надеюсь) был яснее. –

+0

Просто для удовольствия я мог бы указать, что ваш первый пример мог бы так же легко быть «static double a = someCondition? 0: 1;» Не то чтобы ваши примеры не велики, я просто говорю ... :) –

4

В вашем примере, нет никакой разницы; но часто начальное значение является более сложным, чем удобно выразить в одном выражении (например, это List<String>, содержимое которого лучше всего выражается for -loop, или это Method, который может не существовать, поэтому необходимы обработчики исключений) и/или статические поля должны быть установлены в определенном порядке.

4

Иногда вы хотите сделать больше, чем просто присваивать значения статическим переменным. Поскольку вы не можете помещать произвольные выражения в тело класса, вы можете использовать статический блок инициализатора.

3

Технически, вы могли бы обойтись без него. Некоторые предпочитают многострочный код инициализации, чтобы перейти в статический метод. Я очень доволен использованием статического инициализатора для относительно простой многоступенчатой ​​инициализации.

Конечно, я почти всегда делал свою статику final и указывал на немодифицируемый объект.

12

Типичное использование:

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

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

Как бы вы сделать это без статического инициализатора?

+2

Ответ: [Guava] (http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/ collect/ImmutableMap.Builder.html) :) +1 –

+0

@PaulBellora: P – gawi

+0

Другой ответ без дополнительных библиотек: создать статический метод, который инкапсулирует инициализацию 'SET' и использует инициализатор переменной (' private final static Set SET = createValueSet() '). Что, если у вас есть 5 наборов и 2 карты, вы просто сбросите их все в один «статический» блок? – TWiStErRob

0

Статический кодовый блок позволяет инициализировать поля с большим количеством операций, инициализировать поля в другом порядке объявлений, а также может использоваться для условной инициализации.

Более конкретно,

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

не будет работать, так как и б объявлены после того, как AB.

Однако я мог бы использовать статический init. блок, чтобы преодолеть это.

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

8

Обработка исключений при инициализации является еще одной причиной. Например:

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

Это полезно для конструкторов, которые раздражающе проливают проверенные исключения, как выше, или еще более сложная инициализация логики, может быть исключением склонного.

4

static блок может быть использован для инициализации одноэлементного экземпляра, чтобы предотвратить использование синхронизированногоgetInstance() метода.

1

Ключевое слово 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("================="); 
    } 
} 
0

Статический блок инициализации полезно, если один, вы хотите инициализировать статические типы указанного класса, до начала класса первого использования. Последующее использование не будет вызывать никаких статических блоков инициализации. Его прямая противоположность инициализаторам экземпляра, которые инициализируют члены экземпляра,