2012-10-04 2 views
7

Existe-t-il un bon moyen de conserver une référence à un objet créé dans un constructeur qui doit être passé au super constructeur d'une classe étendue (autre que de le rendre accessible depuis le super classe ou en le passant dans le constructeur en tant que paramètre)? Laissez-moi clarifier avec un exemple.Conserver la référence à un nouvel objet passé dans le super constructeur

Prenez cette classe (que je ne peux pas modifier et qui ne me donne pas accès à foo):

class TestA { 
    TestA(Object foo) {} 
} 

Maintenant, je voudrais cette classe étend comme suit:

class TestB extends TestA { 
    Object myCopyOfFoo; 

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

est-il un bon moyen de stocker le new Object() créé dans myCopyOfFoo?

Ni l'un de ces trois idées de travail:

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

(erreur: appel constructeur doit être la première instruction dans un constructeur)

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

(erreur: ne peut pas se référer à un champ d'instance myCopyOfFoo tout en invoquant explicitement un constructeur)

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

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

(Erreur: ne peut pas faire référence à un i méthode de nstance en invoquant explicitement un constructeur)

Je suppose que je pouvais faire ce qui suit, mais il est ni thread-safe, ni élégant:

static Object tempFoo; 

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

Quelqu'un at-il une meilleure idée pour moi? Et pourquoi diable mes deux premières idées ne sont-elles pas légitimes?

Répondre

15

Que diriez-vous:

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; 
    } 
} 

En tant que deuxième constructeur est privé, il ne peut être appelée dans la même classe (ou une classe englobante) de sorte que vous devez juste vous assurer que tout appelant le second constructeur a fait une copie appropriée, comme le fait le premier constructeur.

EDIT: Si votre situation réelle est que vous prenez une copie d'un paramètre existant, cela fonctionnerait ...

class ClassB extends ClassA { 
    private final Foo copyOfInput; 

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

Il est assez laid si :(

+0

Cela ressemble à une bonne solution qui correspond effectivement mon code bien, puisque je suis déjà en utilisant le deuxième constructeur privé dans de nombreux cas de toute façon. Je suis tenté de cocher cette réponse, mais cela semble encore beaucoup de code.J'en doute, mais voyons s'il y a des suggestions encore plus courtes. Mais merci déjà! –

+0

@Markus: J'ai une suggestion potentielle si votre cas * real * prend déjà un paramètre et crée une copie. Si le code que vous avez donné est vraiment représentatif (c'est-à-dire qu'il crée un nouvel objet à partir de rien) alors mon autre suggestion n'aiderait pas. Je vais le modifier cependant. –

0

Qu'est-ce que sur les points suivants:

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

    TestB() { 
     super(myCopyOfFoo); 
    } 
} 

l'objet ne sera initialisés lors de la création d'un nouveau TestB d'objet, donc, en substance ceci fera ce que yo tu veux?

+1

Non, obtenez l'erreur "impossible de référencer myCopyOfFoo avant que le constructeur supertype ait été appelé" –

+1

L'autre problème avec ceci est que le compilateur va aligner l'initialisation de myCopyOfFoo dans le constructeur TestB(). Donc, même si elle ne lance pas d'erreur, elle appellera super() avec null plutôt que le nouvel objet. –

1

Une autre option:

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); 
    } 

} 
Questions connexes