Question

Supposons que j'ai une classe de base B et une classe dérivée D. Je souhaite une méthode foo () dans ma classe de base qui retourne un nouvel objet, quel que soit le type d'instance. Ainsi, par exemple, si j'appelle B.foo (), il retourne un objet de type B, tandis que si j'appelle D.foo (), il retourne un objet de type D; pendant ce temps, la mise en oeuvre réside uniquement dans la classe de base B.

Est-ce possible?

Était-ce utile?

La solution

Ne pas. Faites le " foo " résumé de la méthode.

abstract class B {
    public abstract B foo();
}

Ou recevez une fabrique abstraite via le constructeur de la classe de base:

abstract class B {
    private final BFactory factory;
    protected B(BFactory factory) {
        this.factory = factory;
    }
    public B foo() {
        return factory.create();
    }
}
interface BFactory {
    B create();
}

Ajoutez des types de retour covariants et des génériques à votre goût.

Autres conseils

Tant que chaque classe a un constructeur par défaut:

    public B instance() throws Exception {
        return getClass().newInstance();
    }

Eh bien, je pourrais être en retrait, mais je suppose que depuis "ceci" fait toujours référence à l'objet actuel, vous pouvez faire quelque chose comme

public B foo() {
    return this.getClass().newInstance();
}

ou quelque chose du genre? Si vous créez une instance de D puis appelez d.foo (), vous devriez obtenir une instance de D renvoyée en tant que B. Vous pouvez le renvoyer sous la forme d'un objet brut, mais vous devez être aussi spécifique que possible dans cet exemple, je pense.

Hormis le fait que je pense qu'il existe probablement un défaut de conception si vous souhaitez accomplir cela, vous pouvez essayer l'approche suivante.

Dans votre question, vous utilisez des méthodes statiques (classe), B.foo (), D.foo (), cela ne peut pas être accompli à l'aide de l'héritage, car les méthodes statiques n'ont pas de nature dynamique, elles ne participent pas. dans le système de recherche. Donc, vous n'avez pas assez d'informations de type.

Si vous utilisez une fonction membre foo (), vous pourriez avoir la construction suivante:

public class B {
    public B foo()
    throws IllegalAccessException, InstantiationException {
        return this.getClass().newInstance();
    }
}

public class D  extends B{    
}

public class Test {
    public static final void main(String[] args)
    {
        try {
            System.out.println((new B()).foo());
            System.out.println((new D()).foo());
        } catch (IllegalAccessException e) {
            e.printStackTrace();  
        } catch (InstantiationException e) {
            e.printStackTrace();  
        }
    }
}

Comme le disent les autres réponses, vous pouvez utiliser getClass (). newInstance () s'il existe un constructeur sans argument dans chaque sous-classe (veillez à bien capturer InstantiationException et IllegalAccessException).

Si l'un des constructeurs requiert des arguments, vous pouvez utiliser la réflexion ou (de préférence, à mon avis) une méthode telle que getNewInstance () que vous pouvez remplacer dans la sous-classe uniquement si nécessaire.

par exemple

Thing foo() {
    Thing th = getNewInstance();
    // do some stuff with th
    return th;
}

Thing getNewInstance() {
    return getClass().newInstance();
}

Ensuite, getNewInstance () ne peut être remplacé que si vous en avez vraiment besoin, pour les sous-classes qui n'ont pas le constructeur par défaut.

Thing getNewInstance() {
    return new BigThing(10, ThingSize.METRES);
}

Je pense que cela pourrait être possible d’utiliser la réflexion, c’est-à-dire que dans votre super-classe, vous avez:

public ClassName getFoo() throws InstantiationException, IllegalAccessException
{
    return getClass().newInstance();
}

Où NomClasse est le nom de votre classe de base.

Vous devrez le lancer où vous voulez l'utiliser ... Je ne suis pas sûr que ce soit vraiment une excellente solution!

Éditer: Les méthodes de type newInstance () sont généralement statiques. Bien entendu, vous n'aurez aucune idée du type de votre sous-classe avec une méthode statique.

Je ne pense pas qu'il soit possible d'obtenir une méthode statique pour créer (dynamiquement) une instance d'une sous-classe.

@Rik

Le vrai problème, c’est que j’ai une classe de base abstraite, Thing. Et Thing a une méthode appelée getNextThing () qui renvoie une nouvelle instance de Thing.

Ensuite, j'ai plusieurs sous-classes telles que BigThing, LittleThing, SomethingThing et je ne veux pas continuer à réécrire la méthode getNextThing () pour chacune d'entre elles. Cela semble inutile, puisqu'ils font tous la même chose ...

Est-ce que mon approche est incorrecte?

Je ne sais pas pourquoi vous essayez de faire ce que vous essayez réellement de faire. Fournir plus de contexte pourrait nous permettre de vous aider davantage.

public class B <X extends B>{

public X foo() throws InstantiationException, IllegalAccessException{
    return (X)this.getClass().newInstance();
}
}        
public class C extends B<C>{        

}

Laissez-moi vous offrir ce conseil. La façon dont on enseigne les cours de CS est que les professeurs sont épris d'héritage, mais n'ont pas compris la composition. Je pense que ce que vous pourriez rechercher, c'est la composition. Ainsi, au lieu d'appeler getNextThing sur la chose elle-même, vous devriez peut-être envisager de la mettre en œuvre Iterable

Cela signifie que vous aurez simplement besoin d'écrire un Iterator qui peut résumer la logique d’obtenir la prochaine étape, car cela ne semble pas correspondre à votre modèle d’héritage. Un autre avantage est que vous en tirez de bons périphériques syntaxiques (améliorés pour la compréhension des boucles).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top