Czym różni się inicjator wystąpienia od konstruktora?

82

Innymi słowy, dlaczego potrzebujesz inicjatora instancji? Jaką różnicę lub przewagę masz w pisaniu inicjatora instancji nad konstruktorem?

Ajay
źródło
2
Inicjatory instancji są dość rzadkie (chyba że wpadniesz na kod od kogoś, kto lubi idiom z podwójnym nawiasem klamrowym).
Tom Hawtin - tackline

Odpowiedzi:

109

To wydaje się dobrze to wyjaśniać:

Inicjatory instancji są użyteczną alternatywą dla inicjatorów zmiennych instancji, gdy:

  • kod inicjujący musi przechwytywać wyjątki lub

  • wykonywać wymyślne obliczenia, których nie można wyrazić za pomocą inicjatora zmiennej wystąpienia. Oczywiście zawsze można by taki kod napisać w konstruktorach.

Ale w klasie, która miała wiele konstruktorów, musiałbyś powtórzyć kod w każdym konstruktorze. Dzięki inicjalizatorowi instancji możesz po prostu napisać kod raz, a zostanie on wykonany bez względu na to, jaki konstruktor zostanie użyty do utworzenia obiektu. Inicjatory instancji są również przydatne w anonimowych klasach wewnętrznych, które w ogóle nie mogą deklarować żadnych konstruktorów.

Od: Inicjalizacja obiektu JavaWorld w Javie .

javamonkey79
źródło
17
Z drugiej strony możesz napisać kod raz w jednym konstruktorze i po prostu wywołać go ze wszystkich innych konstruktorów. Ale anonimowe klasy wewnętrzne mają rację.
Tadeusz Kopeć
11
Możesz wywołać to z innych konstruktorów - ale potem znowu powtarzasz wywołanie. Jeśli dodasz nowy konstruktor, musisz pamiętać o dodaniu do niego wywołania. Inaczej jest w przypadku inicjatora instancji.
talonx
5
@talonx, zgadzam się z twoim argumentem dotyczącym zapominania, ale używanie domyślnego zachowania jest równie niebezpieczne. Gdy osoba wspierająca czyta przez konstruktor w starszym kodzie, nie zawsze należy pamiętać o sprawdzaniu możliwych inicjatorów instancji. Podczas gdy jawnie używana funkcja init () będzie się wyróżniać.
Assambar
1
@ javamonkey79: To znaczy, że jeśli wybiorę konstruktora na przykład inicjator dla mojej klasy, to jedyne miejsce, gdzie instancja inicjująca jest przydatna jest podczas pracy z anonimowych klas?
realPK
4
@Assambar Nie możesz przypisać końcowych pól w swojej metodzie init (), ale możesz to zrobić w bloku inicjalizatora.
Timmos
22

Pod względem cyklu życia obiektu nie ma różnicy. Oba są wywoływane w czasie konstrukcji i logicznie rzecz biorąc, blok inicjalizatora można uznać za część konstrukcji.

Z semantycznego punktu widzenia inicjator jest dobrym narzędziem z kilku powodów:

inicjalizator może poprawić czytelność kodu, utrzymując logikę inicjalizacji obok inicjowanej zmiennej:

   public class Universe {
       public int theAnswer;
       {
         int SIX = 6;
         int NINE = 7;
         theAnswer = SIX * NINE;
       }

       // a bunch of other vars
   }

vs

   public class Universe {
       public int theAnswer;

       // a bunch of other vars

       public Universe() {
         int SIX = 6;
         int NINE = 7;
         theAnswer = SIX * NINE;

         // other constructor logic
       }
   }

Inicjatory są wywoływane niezależnie od tego, który konstruktor jest używany.

Inicjatory mogą być używane w anonimowych klasach wewnętrznych, w których konstruktorzy nie mogą.

ykaganovich
źródło
3
To, co masz, jest technicznie „inicjatorem zmiennej instancji”, a nie „inicjatorem instancji” (blok bezpośrednio zagnieżdżony w klasie). Patrz JLS, 3. sekcja 8.6.
Tom Hawtin - tackline
Blok inicjalizatora instancji nie ma nazwy, jak pokazano tutaj . Prawda? Oznaczyłeś kod inicjujący instancję nazwą theAnswer. Czy to jest poprawne? albo coś mi brakuje.
RBT
1
@RBT theAnswerto zadeklarowana zmienna instancji. Jest inicjowany w anonimowym bloku inicjalizatora. Zwróć uwagę na średnik po deklaracji zmiennej.
ykaganovich
10

Jeśli masz wiele konstruktorów i chcesz, aby jakiś wspólny kod był wykonywany dla każdego konstruktora, możesz użyć inicjatora instancji, ponieważ jest on wywoływany dla wszystkich konstruktorów.

Rahul Garg
źródło
4

Generalnie unikałbym idiomu inicjatora instancji - jedyną prawdziwą zaletą, jaką daje on w porównaniu z inicjatorami zmiennych, jest obsługa wyjątków.

A ponieważ metoda init (wywoływana z konstruktora) może również obsługiwać wyjątki, a także centralizuje kod konfiguracji konstruktora, ale ma tę zaletę, że może działać na wartościach parametrów konstruktora, powiedziałbym, że inicjator wystąpienia jest nadmiarowy i dlatego powinien być unikać.

CPerkins
źródło
1
Musiałbyś ręcznie wywołać metodę init we WSZYSTKICH konstruktorach.
Stephan
2
@Alex Dobra uwaga, ale ponieważ większość klas z wieloma konstruktorami ma wspólną logikę, i tak mają tendencję do wywoływania się nawzajem. Przynajmniej na większości moich zajęć.
CPerkins
3

Prawdziwa zaleta instancji inicjalizatorów ponad konstruktorów jest widoczne, gdy używamy anonimowej klasy wewnętrznej .

Anonimowe klasy wewnętrzne nie mogą mieć konstruktora (ponieważ są anonimowe) , więc są całkiem naturalne, np . Inicjalizatory .

padipistka
źródło
1

W momencie tworzenia obiektu, jeśli chcemy wykonać inicjalizację zmiennych instancji, to powinniśmy wybrać Konstruktor, poza czynnością inicjalizacyjną, jeśli chcemy wykonać jakąkolwiek czynność w momencie tworzenia obiektu to na przykład blok.

Nie możemy zastąpić konstruktora blokiem instancji, ponieważ konstruktor może przyjmować argumenty, ale blok instancji nie może przyjmować argumentów.

Nie możemy zastąpić konstruktora bloku wih instancji, ponieważ klasa może zawierać więcej niż jeden konstruktor. Jeśli chcemy zastąpić blok instancji konstruktorem, to w każdym konstruktorze musimy napisać kod blokowy instancji, ponieważ w czasie wykonywania nie możemy się spodziewać, który konstruktor zostanie wywołany, niepotrzebnie zwiększy zduplikowany kod.

Przykład:

class MyClass{

    static int object_count = 0;

    MyClass(){
        object_count++;
    }

    MyClass(int i){

        object_count++;
    }

    void getCount() {

        System.out.println(object_count);
    }

    public static void main(String... args) {
        MyClass one = new MyClass();
        MyClass two = new MyClass(2);
        two.getCount();
    }
}

Wynik : 2

class MyClass{

    static int object_count = 0;

    {
        object_count++;
    }

    MyClass(){

    }

    MyClass(int i){     

    }

    void getCount() {

        System.out.println(object_count);
    }

    public static void main(String... args) {
        MyClass one = new MyClass();
        MyClass two = new MyClass(2);
        two.getCount();
    }
}

Wynik : 2

NPE
źródło
0

Inicjator jest sposobem udostępniania kodu między konstruktorami i sprawia, że ​​kod jest bardziej czytelny, jeśli inicjator jest używany z deklaracją zmiennej.

Kompilator Java kopiuje bloki inicjalizatora do każdego konstruktora. Dlatego to podejście może służyć do udostępniania bloku kodu między wieloma konstruktorami. Dokumentacja Oracle

dnyanesh
źródło