Există vreun avantaj pentru orice abordare?
Exemplul 1:
class A {
B b = new B();
}
Exemplul 2:
class A {
B b;
A() {
b = new B();
}
}
{ a = new A(); }
Verifica Sun's explicație și consiliere
De la acest tutorial:
Domeniul de declarații, cu toate acestea, nu sunt parte din orice metodă, astfel încât acestea nu pot fi executate ca declarații. În schimb, compilatorul Java generează exemplu-câmp cod de inițializare în mod automat și pune-l în constructor sau constructori pentru clasa. Codul de inițializare este introdus într-un constructor în ordinea în care apare în codul sursă, ceea ce înseamnă că un câmp de inițializare pot folosi valorile inițiale de domenii declarate înainte.
În plus, ați putea dori să lazily initialize domeniul tau. În cazurile în care inițializează un câmp este o operație costisitoare, puteți inițializa cât mai curând, deoarece este nevoie de:
ExpensiveObject o;
public ExpensiveObject getExpensiveObject() {
if (o == null) {
o = new ExpensiveObject();
}
return o;
}
Și în cele din urmă (după cum a subliniat de Lege), de dragul de management de dependență, este mai bine să avoid folosind " noi " operator oriunde în clasa ta. În schimb, folosind Injectare Dependență este de preferat - adică să lase pe altcineva (alta clasa/cadru) instantia și se injectează dependențe în clasa ta.
O altă opțiune ar fi de a utiliza de Injectare Dependență.
class A{
B b;
A(B b) {
this.b = b;
}
}
Acest lucru elimină responsabilitatea de a crea " B "obiect de constructorul de "A". Acest lucru va face codul mai testabile și mai ușor să se mențină pe termen lung. Ideea este de a reduce cuplajul dintre cele două clase " a " și "B". Un beneficiu pe care acest lucru vă oferă este că acum puteți trece orice obiect care se extinde " B "(sau implementează " B "dacă este o interfață) la" A " 's constructorul și va funcționa. Un dezavantaj este că trebuie să renunți încapsulare a B
obiect, astfel încât acesta este expus la apelantul a " a " de constructor. Te'll trebuie să ia în considerare dacă beneficiile sunt în valoare de acest tip de comerț-off, dar în multe cazuri sunt.
M-am ars într-un mod interesant azi:
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
@Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
Vezi greșeală? Se pare că o = null
inițializare se numește după superclasa constructorul este apelat. De la superclasa apeluri constructor init(), inițializarea " a " e urmat de o = null
de inițializare.
mea personal "regula" (rar rupte) este de a:
Deci mi-ar fi cod, cum ar fi:
public class X
{
public static final int USED_AS_A_CASE_LABEL = 1; // only exception - the compiler makes me
private static final int A;
private final int b;
private int c;
static
{
A = 42;
}
{
b = 7;
}
public X(final int val)
{
c = val;
}
public void foo(final boolean f)
{
final int d;
final int e;
d = 7;
// I will eat my own eyes before using ?: - personal taste.
if(f)
{
e = 1;
}
else
{
e = 2;
}
}
}
În acest fel sunt întotdeauna 100% sigur unde să te uiți pentru variabile declarații (la începutul unui bloc), și sarcinile lor (de îndată ce este logic după declarația). Acest vânturi potențial a fi mai eficientă, deoarece nu vă inițializa o variabilă cu o valoare care nu este utilizat (de exemplu declare și să init vars si apoi arunca o excepție înainte de jumatate din cei vars nevoie pentru a avea o valoare). De asemenea, nu faci rost de inițializare (cum ar fi int i = 0; și apoi, mai târziu, înainte de a "i" este folosit, nu i = 5;.
Am valoare consistenta foarte mult, astfel încât în urma acestei "regula" este ceva ce face tot timpul, și-l face mult mai ușor de a lucra cu codul de când nu't trebuie să vâneze în jurul pentru a găsi lucruri.
Kilometraj dvs. poate varia.
Exemplul 2 este mai puțin flexibil. Dacă adăugați un alt constructor, aveți nevoie să vă amintiți pentru a instantia domeniul în care constructorul fel de bine. Doar instantia domeniul direct, sau de a introduce încărcare leneș undeva într-un getter.
Dacă instanțierea necesită mai mult decât doar un simplu "noi", utilizați un bloc de inițializare. Acest lucru va fi rulat indiferent de constructorul folosit. E. g.
public class A {
private Properties properties;
{
try {
properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("file.properties"));
} catch (IOException e) {
throw new ConfigurationException("Failed to load properties file.", e); // It's a subclass of RuntimeException.
}
}
// ...
}
Să înțeleg că este aproape o chestiune de gust, cât de inițializare este simplu și nu't nevoie de nici o logica.
Constructorul abordare este un pic mai fragile, dacă nu't folosi un bloc de inițializare, pentru că, dacă mai târziu se adaugă un al doilea constructor și să uitați pentru a inițializa b acolo,'ll obține un null b doar atunci când se utilizează ultima constructor.
Vezi http://java.sun.com/docs/books/tutorial/java/javaOO/initial.html pentru mai multe detalii despre inițializare în Java (și pentru explicații pe initalizer blocuri și alte nu este bine cunoscut de inițializare caracteristici).
Folosind fie injectare dependență sau lazy initialization este întotdeauna de preferat, ca deja explicat în alte răspunsuri.
Când don't vrea sau poate't de a folosi acele modele, și pentru tipuri de date primitive, există trei motive imperioase care mă pot gândi de ce-l's de preferat pentru a inițializa atributele de clasă în afara constructor:
Ambele metode sunt acceptabile. Rețineți că, în acest din urmă caz b=new B()
nu poate obține inițializat dacă există un alt constructor prezent. Cred că de inițializare cod afara constructor de drept comun constructor și codul este executat.
Am'nu am văzut în răspunsurile:
Un avantaj posibil de a avea inițializarea la data de declarație ar putea fi cu zilele noastre IDE's unde puteți sări cu ușurință la declararea unei variabile (cea mai mare parte
Ctrl-<hover_over_the_variable>-<left_mouse_click>
) de oriunde în cod. Apoi veți vedea imediat de valoarea acestei variabile. În caz contrar, va trebui să "căutare" de la locul unde inițializarea se face (mai ales: constructor).
Acest avantaj este, desigur, secundar toate celelalte raționamentele logice, dar pentru unii oameni care "caracteristică" ar putea fi mai important.
Nu este unul mai subtil motiv pentru a inițializa în afara constructor care nimeni n-a menționat mai înainte (foarte specifice trebuie să spun). Dacă sunteți folosind UML instrumente pentru a genera diagrame de clase din cod (reverse engineering), cele mai multe dintre instrumentele cred că se va nota de inițializare de Exemplu 1 și se va transfera la o diagramă (dacă preferați pentru a arăta valorile inițiale, așa cum fac eu). Ei nu vor lua aceste valori inițiale din Exemplul 2. Din nou, acest lucru este un motiv foarte specific - dacă lucrați cu UML instrumente, dar odată ce am înțeles asta, am încercat să-mi ia toate valorile implicite afara de constructor, cu excepția cazului, după cum a fost menționat mai înainte, există o problemă de excepție posibilă aruncarea sau complicat logica.
A doua opțiune este de preferat, deoarece permite de a utiliza diferite logică în ctors pentru clasa instanțierea și de a folosi ctors înlănțuirea. E. g.
class A {
int b;
// secondary ctor
A(String b) {
this(Integer.valueOf(b));
}
// primary ctor
A(int b) {
this.b = b;
}
}
Deci, cea de-a doua opțiuni este mult mai flexibil.
class MyClass extends FooClass {
String a = null;
public MyClass() {
super(); // Superclass calls init();
}
@Override
protected void init() {
super.init();
if (something)
a = getStringYadaYada();
}
}
Cu privire la cele de mai sus,
String a = null;
null init ar putea fi evitate, deoarece oricum l's implicită. Cu toate acestea, dacă ai nevoie de o altă valoare implicită, apoi, din cauza necontrolate de inițializare pentru, Mi-ar stabili după cum urmează:
class MyClass extends FooClass
{
String a;
{
if( a==null ) a="my custom default value";
}
...
L's destul de diferite, de fapt:
Declarația se întâmplă înainte de construcție. Deci, spun că dacă unul a initializat variabila (b în acest caz), la ambele locuri, constructorul's initialization va înlocui pe cel făcut la nivel de clasă.
Deci, declara variabile la nivel de clasă, inițializați-le în constructor.