2012-10-04 9 views
7

C'è un buon modo per mantenere un riferimento a un oggetto creato in un costruttore che deve essere passato al super costruttore di una classe estesa (diverso da quello che lo rende accessibile dalla super classe o passarlo nel costruttore come parametro)?Mantenere riferimento al nuovo oggetto passato in super costruttore

Vorrei chiarire con un esempio. Prendete questa classe (che non posso modificare e che non mi dà l'accesso a foo):

class TestA { 
    TestA(Object foo) {} 
} 

Ora, vorrei estende questa classe come segue:

class TestB extends TestA { 
    Object myCopyOfFoo; 

    TestB() { 
     super(new Object()); 
    } 
} 

C'è un buon modo per memorizzare il creato new Object() in myCopyOfFoo?

Nessuno di questi tre idee funzionano:

TestB() { 
    myCopyOfFoo = new Object(); 
    super(myCopyOfFoo); 
} 

(Errore: chiamata al costruttore deve essere la prima istruzione in un costruttore)

TestB() { 
    super(myCopyOfFoo = new Object()); 
} 

(Errore: non può fare riferimento a un myCopyOfFoo campo di istanza invocando esplicitamente un costruttore)

TestB() { 
    super(makeFoo()); 
} 

Object makeFoo() { 
    myCopyOfFoo = new Object(); 
    return myCopyOfFoo; 
} 

(Errore: impossibile fare riferimento a un Metodo nstance mentre invocando esplicitamente un costruttore)

Credo che avrei potuto fare quanto segue, ma non è né thread-safe né elegante:

static Object tempFoo; 

TestB() { 
    super(tempFoo = new Object()); 
    myCopyOfFoo = tempFoo; 
} 

Qualcuno ha un'idea migliore per me? E perché mai le mie prime due idee non sono legittime?

risposta

15

ne dite:

class TestB extends TestA { 
    Object myCopyOfFoo; 

    // I assume you actually wanted this to take a parameter called foo? 
    // I've left it as per the question... 
    TestB() { 
     this(new Object()); 
    } 

    private TestB(Object copy) { 
     super(copy); 
     myCopyOfFoo = copy; 
    } 
} 

Come il secondo costruttore è privato, si può essere chiamato solo all'interno della stessa classe (o di una classe di inclusione) in modo che solo bisogno di fare in modo che tutto ciò chiamando il secondo costruttore ha fatto una copia appropriata, come fa il primo costruttore.

EDIT: Se il vostro vero situazione è che si sta prendendo una copia di un parametro esistente, allora questo dovrebbe funzionare ...

class ClassB extends ClassA { 
    private final Foo copyOfInput; 

    ClassB(Foo input) { 
     super(input = input.clone()); 
     copyOfInput = input; 
    } 
} 

E 'abbastanza brutto però :(

+0

Questo appare come una buona soluzione che si inserisce in realtà il mio codice bene, dal momento che sto già utilizzando il secondo costruttore privato, in molti casi comunque. Sono tentato di segno di spunta già questa risposta, ma sembra ancora come un sacco di codice.Ne dubito, ma vediamo se ci sono suggerimenti ancora più brevi. Ma grazie già! –

+0

@Markus: ho un potenziale suggerimento se il tuo caso * real * effettivamente prende già un parametro e crea una copia. Se il codice che hai fornito è realmente rappresentativo (cioè sta creando un nuovo oggetto dal nulla), il mio altro suggerimento non sarebbe di aiuto. Lo modificherò comunque. –

0

Cosa qui di seguito:

class TestB extends TestA { 
    Object myCopyOfFoo = new Object(); 

    TestB() { 
     super(myCopyOfFoo); 
    } 
} 

l'oggetto viene inizializzato solo quando si crea un nuovo oggetto TestB, quindi in sostanza questo farà quello yo vuoi?

+1

No, ottieni l'errore "Impossibile fare riferimento a myCopyOfFoo prima che il costruttore supertype sia stato chiamato" –

+1

L'altro problema con questo è che il compilatore inline l'inizializzazione di myCopyOfFoo nel costruttore TestB(). Quindi, anche se non generava un errore, chiamava super() con null anziché con il nuovo Object. –

1

Un'altra opzione:

public class TestB extends TestA { 

    Object myCopyOfFoo; 

    private TestB(Object foo) { 
     super(foo); 
     myCopyOfFoo = foo; 
    } 

    public static TestB createInstance() { 
     Object foo = new Object(); 
     return new TestB(foo); 
    } 

}