Java générique de la méthode de l'héritage et de remplacer les règles

J'ai une classe abstraite qui a une méthode générique et je veux remplacer la méthode générique en substituant des types spécifiques au paramètre générique. Donc, dans le pseudo-code, j'ai ce qui suit:

public abstract class GetAndParse {
  public SomeClass var;

  public abstract <T extends AnotherClass> void getAndParse(T... args);
}

public class Implementor extends GetAndParse {
  // some field declarations

  // some method declarations

  @Override
  public <SpecificClass> void getAndParse(SpecificClass... args) {
    // method body making use of args
  }
}

Mais pour une raison quelconque, Je ne suis pas autorisé à le faire? Ai-je fait une sorte d'erreur de syntaxe ou est ce genre d'héritage et impérieuses pas permis? Plus précisément, je reçois une erreur à propos de @Override parce que l'IDE eclipse ne cesse de me rappeler d'implémenter getAndParse.

Voici comment Je veux que le code ci-dessus fonctionne. Ailleurs dans mon code, il existe une méthode qui attend des instances d'objets qui implémentent GetAndParse ce qui signifie spécifiquement qu'ils ont une méthode getAndParse que je peux utiliser. Quand j'appelle getAndParse sur cette instance, le compilateur vérifie si j'ai utilisé des instances spécifiques de T de la manière appropriée, donc en particulier T devrait s'étendre AnotherClass et il devrait être SpecificClass.

26
demandé sur davidk01 2011-03-18 03:19:53

5 réponses

Ce que nous avons ici, ce sont deux méthodes différentes avec des paramètres de type individuels chacune.

public abstract <T extends AnotherClass> void getAndParse(Args... args);

C'est une méthode avec un paramètre de type nommé T, et délimité par AnotherClass, ce qui signifie que chaque sous-type de AnotherClass est autorisé en tant que paramètre de type.

public <SpecificClass> void getAndParse(Args... args)

C'est une méthode avec un paramètre de type nommé SpecificClass, délimité par Object (ce qui signifie que chaque type est accueilli comme un paramètre de type). Voulez-vous vraiment cela?

Le paramètre type est-il utilisé à l'intérieur de Args? Je pense que le problème serait y.


Modifier:

La signification de

public abstract <T extends AnotherClass> void getAndParse(T... args);

Est le appelant de la méthode peut décider avec quel type de paramètre qu'il veut appeler la méthode, tant que c'est une sous-type de AnotherClass. Cela signifie qu'en effet la méthode peut être appelée avec n'importe quel objet de type AnotherClass.

Puisque l'appelant peut décider du paramètre type, vous ne pouvez pas dans une sous-classe affiner le type de paramètre à SpecificClass - ce ne serait pas une implémentation de la méthode, mais une autre méthode avec le même nom (surcharge).

Peut-être que vous voulez quelque chose comme ceci:

public abstract class GetAndParse<T extends AnotherClass> {
  public SomeClass var;

  public abstract void getAndParse(T... args);
}

public class Implementor extends GetAndParse<SpecificClass> {
  // some field declarations

  // some method declarations

  @Override
  public void getAndParse(SpecificClass... args) {
    // method body making use of args
  }
}

Maintenant, la méthode getAndParse implémente la méthode de la classe parent.

27
répondu Paŭlo Ebermann 2011-03-18 13:54:35

Vous voyez ce problème à cause du concept appelé "effacement" dans les génériques Java. Java utilise "erasure" pour prendre en charge la rétrocompatibilité. c'est-à-dire le code Java qui n'a pas utilisé de génériques.

Procédure D'Effacement:
Le compilateur effectuera d'abord une vérification de type, puis supprimera(effacera) tous les paramètres de type autant que possible, et insérera également la TypeCasting si nécessaire.

Exemple:

public abstract <T extends AnotherClass> void getAndParse(T paramAnotherClass);

Deviendra

public abstract void getAndParse(AnotherClass paramAnotherClass);

En classe "Un réalisateur.java",

Le code

public <SpecificClass> void getAndParse(T paramAnotherClass)

Deviendra

public void getAndParse(SpecificClass paramAnotherClass){  }

Le compilateur verra que vous n'avez pas implémenté correctement la méthode abstraite. Il existe une incompatibilité de type entre la méthode abstraite et la méthode implémentée. C'est pourquoi vous voyez l'erreur.

Plus de détails peuvent être trouvés ici. http://today.java.net/pub/a/today/2003/12/02/explorations.html

10
répondu kensen john 2011-03-18 01:26:57

Non, ce n'est pas valide. Que se passerait-il si quelqu'un avec une référence GetAndParse l'appelait avec une classe différente s'étendant AnotherClass?

1
répondu Erik 2011-03-18 00:44:21

Cela devient un non-sens quand quelqu'un a une référence à taper GetAndParse et essaie d'appeler la méthode getAndParse. Si le Chat et le chien étendent un Autreclasse. Je devrais m'attendre à pouvoir appeler getandparse#getAndParse avec un chat ou un chien. Mais la mise en œuvre a essayé de le restreindre et de le rendre moins compatible!

1
répondu Affe 2011-03-18 00:45:12

Vous ne pouvez pas Remplacer par un type spécifique T car il n'y a en fait (au niveau du bytecode si vous le souhaitez) qu'une seule méthode getAndParse en raison de l'effacement de type (Voir autre réponse):

   public abstract void getAndParse(AnotherClass... args); // (1)

Pour chaque type de T, la même méthode est utilisée.

Vous pouvez surcharger (je pense):

   public void getAndParse(SpecificClass... args); // (2)

, Mais ce ne sera pas une méthode différente de (1) et il sera pas être appelé par le code générique:

  T x = whatever;
  object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass
1
répondu ysdx 2011-03-18 02:03:31