2011-07-20 13 views
24

Jaki jest sens "Instance Initializers" w Javie?
Czy nie możemy po prostu wstawić tego bloku kodu na początku konstruktora?Dlaczego inicjatory instancji Java są inicjowane?

+0

To nie będzie wielka sprawa, jeśli java rids tej funkcji. – irreputable

+10

@irreputable, rzadko kiedy potrzebuję ich, ale anonimowe klasy nie mogą mieć konstruktorów, ale mogą mieć inicjatory instancji, więc potrzebujemy ich w języku. – Kaj

+1

Przy inicjalizowaniu pól inicjatora Kaj można wykonać zadanie – irreputable

Odpowiedz

23

Można rzeczywiście umieścić kod na początku każdego konstruktora. Jednak to właśnie jest punktem inicjalizatora instancji: jego kod jest stosowany do konstruktorów wszystkich, co może być przydatne, jeśli masz wiele konstruktorów i trochę kodu, który jest wspólny dla wszystkich z nich.

(Jeśli dopiero zaczynasz programowanie, być może nie wiedziałeś, że możliwe jest utworzenie wielu konstruktorów dla tej samej klasy (o ile przyjmują różne parametry), co jest znane jako przeciążanie konstruktora Przeciążenie konstruktora Jeśli masz tylko jeden konstruktor, inicjator instancji nie jest zbyt użyteczny (Edycja: chyba, że ​​nadużywasz go w twórczy sposób, jak pokazano w innych odpowiedziach).

+0

Ponadto, nawet przy pojedynczym konstruktorze, deklarowanie i inicjowanie razem jest bardziej czytelne i nieco mniej ryzykowne niż deklarowanie i inicjowanie tutaj. –

7

Możesz użyć inicjatora instancji, gdy deklarujesz anonimowa klasa, np. gdy popełniamy the Double Brace Initialization Idiom.

List<String> mylist = new ArrayList<String>(){{add("a"); add("b"); add("c");}}; 

Tutaj można zainicjować obiekt, nawet jeśli nie można dodać nic do konstruktora (ponieważ klasa jest anonimowa).

+2

W tym konkretnym przypadku jednak zaleca się używanie 'java.util.Arrays. asList (T ... ts) 'zamiast :-) –

37

Używam ich bardzo często, zwykle do tworzenia i wypełniania mapę w jednej instrukcji (zamiast używać brzydki blok statyczny):

private static final Map<String, String> CODES = new HashMap<String, String>() { 
    { 
     put("A", "Alpha"); 
     put("B", "Bravo"); 
    } 
}; 

Jeden ciekawy i przydatny okrasa do tego jest stworzenie niemodyfikowalne mapę w jednym stwierdzeniem:

private static final Map<String, String> CODES = 
    Collections.unmodifiableMap(new HashMap<String, String>() { 
    { 
     put("A", "Alpha"); 
     put("B", "Bravo"); 
    } 
}); 

Way schludny niż przy użyciu bloków statycznych i radzenia sobie z zadaniami do osobliwych końcowy itp

I jeszcze wskazówka: nie bój się stworzyć metody zbyt upraszczające instancji bloku:

private static final Map<String, String> CODES = new HashMap<String, String>() { 
    { 
     put("Alpha"); 
     put("Bravo"); 
    } 

    void put(String code) { 
     put(code.substring(0, 1), code); 
    } 
}; 
+3

Dla osób używających inicjalizatorów instancji do gromadzenia populacji, patrz [Guava Library] (http://code.google.com/p/guava-libraries/) as bardziej elegancka i mocniejsza alternatywa. Klasa ['Maps'] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Maps.html) zapewnia ładne narzędzia Map i ich klasy' Immutable * 'są szczególnie miłe dla opisanego tu zastosowania, zobacz ['ImmutableMap'] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ImmutableMap.html). – dimo414

+0

@Bohemian Jestem zdezorientowany, jak można było wywołać put(); ?? bez poprzedzającej go nazwy zmiennej? – latenightcode

+2

@goldencalf to klasa anonimowa, która jest podklasą (w locie) *, więc 'put()' jest metodą instancji, która jest niejawnie wywoływana na 'this' - tak jak możesz wywołać' toString() 'od dowolnej metody instancji bez konieczności kodowania' this.toString() '. W przykładzie dodałem przeciążoną wersję 'put()', która przyjmuje tylko jeden parametr i jest widoczna tylko w definicji klasy. – Bohemian

5

Od wszystkich przykładach kod tutaj używać anonimowych klas, wrzuciłem to (nieco przerażające) klasy, która demonstruje razem przy użyciu inicjalizatorów instancji w klasie "właściwej". Możesz ich użyć do złożonego przetwarzania lub obsługi wyjątków w czasie inicjalizacji. Zauważ, że te bloki są uruchamiane przed uruchomieniem konstruktor, ale konstruktor jest prowadzony przed inicjalizatorów w klasie dzieci są prowadzone:

import java.util.Scanner; 

public class InstanceInitializer { 
    int x; 
    { 
     try { 
      System.out.print("Enter a number: "); 
      x = Integer.parseInt(new Scanner(System.in).nextLine()); 
     } catch (NumberFormatException e) { 
      x = 0; 
     } 
    } 

    String y; 
    { 
     System.out.print("Enter a string: "); 
     y = new Scanner(System.in).nextLine(); 
     for(int i = 0; i < 3; i++) 
      y += y; 
    } 

    public InstanceInitializer() { 
     System.out.println("The value of x is "+x); 
     System.out.println("The value of y is "+y); 
    } 

    public static class ChildInstanceInitializer extends InstanceInitializer { 
     { 
      y = "a new value set by the child AFTER construction"; 
     } 
    } 

    public static void main(String[] args){ 
     new InstanceInitializer(); 
     new InstanceInitializer(); 
     System.out.println(); 
     System.out.println(new ChildInstanceInitializer().y); 
     // This is essentially the same as: 
     System.out.println(new InstanceInitializer(){ 
      {y = "a new value set by the child AFTER construction";} 
     }.y); 
    } 
} 

This wyjść (coś podobnego):

Enter a number: 1 
Enter a string: a 
The value of x is 1 
The value of y is aaaaaaaa 
Enter a number: q 
Enter a string: r 
The value of x is 0 
The value of y is rrrrrrrr 

Enter a number: 3 
Enter a string: b 
The value of x is 3 
The value of y is bbbbbbbb 
a new value set by the child AFTER construction 
Enter a number: s 
Enter a string: Hello 
The value of x is 0 
The value of y is HelloHelloHelloHelloHelloHelloHelloHello 
a new value set by the child AFTER construction 

Zawiadomienie łańcuch "nowej wartości" nie zostanie ustawiony, dopóki nie zostanie wywołany konstruktor klasy macierzystej.

Powiązane problemy