11 votes

Conserver la référence au nouvel objet passé dans le super constructeur

Existe-t-il un bon moyen de conserver une référence à un objet créé dans un constructeur qui doit être transmis au super constructeur d'une classe étendue (autre que de le rendre accessible à partir de la super classe ou de le transmettre au constructeur en tant que paramètre) ?

Permettez-moi de clarifier ce point à l'aide d'un exemple. Prenons cette classe (que je ne peux pas modifier et qui ne me donne pas accès à foo) :

class TestA {
    TestA(Object foo) {}
}

J'aimerais maintenant étendre cette classe comme suit :

class TestB extends TestA {
    Object myCopyOfFoo;

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

Existe-t-il une bonne façon de stocker les données créées new Object() en myCopyOfFoo ?

Aucune de ces trois idées ne fonctionne :

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

(Erreur : L'appel au constructeur doit être la première déclaration dans un constructeur)

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

(Erreur : Cannot refer to an instance field myCopyOfFoo while explicitly invoking a constructor)

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

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

(Erreur : Impossible de faire référence à une méthode d'instance lors de l'invocation explicite d'un constructeur)

Je suppose que je pourrais faire ce qui suit, mais ce n'est ni sûr pour les threads ni élégant :

static Object tempFoo;

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

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

19voto

Jon Skeet Points 692016

Que diriez-vous de.. :

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

Le second constructeur étant privé, il ne peut être appelé qu'au sein de la même classe (ou d'une classe englobante). Il suffit donc de s'assurer que toute personne appelant le second constructeur a effectué une copie appropriée, comme le fait le premier constructeur.

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

class ClassB extends ClassA {
    private final Foo copyOfInput;

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

C'est quand même assez moche :(

1voto

Ole V.V. Points 24677

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

}

0voto

John Farrelly Points 3334

Qu'en est-il de ce qui suit :

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

    TestB() {
        super(myCopyOfFoo);
    }
}

L'objet ne sera initialisé que lors de la création d'un nouvel objet TestB, ce qui revient à dire que cela fera ce que vous voulez ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X