2015-02-12 4 views
5

вы можете объяснить мне, какая разница между:Java: Статическая инициализация

public class Test { 

    public static final Person p; 

    static { 
     p = new Person(); 
     p.setName("Josh"); 
    } 

} 

и

public class Test { 

    public static final Person p = initPerson(); 

    private static Person initPerson() { 
     Person p = new Person(); 
     p.setName("Josh"); 
     return p; 
    } 

} 

Я всегда использовал второй, но есть какая-то разница с статическим блоком инициализации ?

ответ

7

Есть, конечно, технические отличия (вы могли бы вызвать статический метод несколько раз в своем классе, если хотите, вы могли бы вызывать его через отражение и т. Д.), Но, предполагая, что вы не делаете ничего из этого обмана, Правильно - оба подхода фактически идентичны.

Я также предпочитаю подход, основанный на методе, поскольку он дает красивое имя блоку кода. Но это почти полностью стилистический подход.

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

Принимая это немного дальше: если у меня есть два статических поля, а один зависит от другого, то я объявлю два метода и второй метод беру первую переменную в качестве явного аргумента. Мне нравится сохранять мои статические методы инициализации полностью без состояния, что значительно облегчает рассуждение о том, что должно произойти, когда (и какие переменные, которые он предполагает, уже созданы).

Так, что-то вроде:

public class Test { 
    public static final Person p = initPerson(); 
    public static final String pAddress = lookupAddress(p); 

    /* implementations of initPerson and lookupAddress omitted */ 
} 

Это очень ясно, смотря на то, что (а) вам не нужно pAddress инициализировать p, и (б) вы сделать необходимо p для инициализации lookupAddress.На самом деле, компилятор даст вам ошибку компиляции («незаконная опережающую ссылку»), если вы пробовали их в обратном порядке, и ваши статические поля были не- final:

public static String pAddress = lookupAddress(p); // ERROR 
public static Person p = initPerson(); 

Вы бы потерять эту ясность и безопасность с статическим блоки. Это компилируется нормально:

static { 
    pAddress = p.findAddressSomehow(); 
    p = new Person(); 
} 

... но это будет не в состоянии во время выполнения, так как в p.findAddressSomehow(), p имеет значение null по умолчанию.

+0

, поэтому для подведения итогов как статический блок, так и статическая часть инициализации будет выполняться только один раз - это то, что вы имеете в виду правильно. – vikeng21

+0

Это правильно. – yshavit

+1

Это не просто название блока, также важно обращение к управлению: метод просто * возвращает * значение, тогда как блок init вставляет его в переменную. Поскольку система статического типа гарантирует, что метод вернет значение, это способствует удобочитаемости и правильности. Блок init может выполнять или не выполнять назначение, и между блоком инициализации и переменной нет жесткой связи. –

1

initPerson требует вызова в какой-то момент, тогда как статический блок выполняется при создании объекта Test.

+1

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

3

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

http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html

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

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

+0

За исключением того, что в этом случае статический метод является закрытым (это означает, что только этот класс может его вызывать) и только один раз запускается при инициализации класса. – yshavit

+0

Я видел ваше редактирование, но в этом случае переменная 'final' - поэтому ее нельзя повторно инициализировать. – yshavit

+0

ОК, это личное. Но он также будет выполняться каждый раз, когда вы его вызываете. Также 0 раз, если вы забыли позвонить. В этом примере его никогда не называют, но я думаю, что это была ошибка. – Simulant

1

Статический объект перед функцией указывает, что вы можете использовать эту функцию, вызвав ее в самом дескрипторе имени класса. Например, если вы хотите создать объект Person вне класса вы можете написать

Person p = Test.initPerson(); 

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

Смежные вопросы