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 pour le paramètre générique. Donc, en pseudo-code, j'ai les éléments suivants:
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é à faire cela? Est-ce que je fais une sorte d'erreur de syntaxe ou est-ce que ce genre d'héritage et de substitution est interdit? Plus précisément, je reçois une erreur à propos de @Override
car Eclipse IDE ne cesse de me rappeler d'implémenter getAndParse
.
Voici comment je veux que le code ci-dessus fonctionne. Quelque part dans mon code, une méthode attend des instances d'objets implémentant GetAndParse
, ce qui signifie spécifiquement qu'elles disposent d'une méthode getAndParse
que je peux utiliser. Lorsque j'appelle getAndParse
sur cette instance, le compilateur vérifie si j'ai utilisé les instances spécifiques de T
de manière appropriée. Ainsi, en particulier, T
devrait étendre AnotherClass
et être SpecificClass
.
Nous avons ici deux méthodes différentes avec des paramètres de type individuels.
public abstract <T extends AnotherClass> void getAndParse(Args... args);
Il s'agit d'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)
Il s'agit d'une méthode avec un paramètre de type nommé SpecificClass
, délimité par Object
(ce qui signifie que chaque type est autorisé en tant que paramètre de type). Tu veux vraiment ça?
Le paramètre type est-il utilisé dans Args
? Je pense que le problème serait là.
Le sens de
public abstract <T extends AnotherClass> void getAndParse(T... args);
est que le appelant de la méthode peut décider avec quel paramètre de type il veut appeler la méthode, tant qu'il s'agit d'un sous-type de AnotherClass
. Cela signifie qu’en réalité la méthode peut être appelée avec n’importe quel objet de type AnotherClass
.
Etant donné que l'appelant peut décider du paramètre type, vous ne pouvez pas, dans une sous-classe, limiter le type du paramètre à SpecificClass
. Il ne s'agirait pas d'une implémentation de la méthode, mais d'une autre méthode portant le même nom (surcharge).
Peut-être que vous voulez quelque chose comme ça:
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.
Vous voyez ce problème à cause du concept appelé "Effacement" dans Java Generics . Java utilise "effacement" pour prendre en charge la compatibilité descendante. C'est-à-dire du code Java qui n'utilisait pas de génériques.
Procédure d'effacement:
Le compilateur fera d’abord une vérification de type, puis supprimera (effacera) tous les paramètres de type autant que possible, et insérera également TypeCasting si nécessaire.
exemple:
public abstract <T extends AnotherClass> void getAndParse(T paramAnotherClass);
va devenir
public abstract void getAndParse(AnotherClass paramAnotherClass);
En classe "Implementor.Java",
Le code
public <SpecificClass> void getAndParse(T paramAnotherClass)
va devenir
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
Non, ce n'est pas valide. Que se passerait-il si une personne avec une référence GetAndParse
l'appelait avec un différent classe prolongeant AnotherClass
?
Cela devient un non-sens quand quelqu'un a une référence pour taper GetAndParse et tente d'appeler la méthode getAndParse. Si chat et chien étendent une autre classe. Je devrais m'attendre à pouvoir appeler GetAndParse # getAndParse avec un chat ou un chien. Mais la mise en œuvre a tenté de le restreindre et de le rendre moins compatible!
Vous ne pouvez pas override sur 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 du type effacement (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 le (je pense):
public void getAndParse(SpecificClass... args); // (2)
mais ce ne sera pas une méthode différente de (1) et il sera appelé pas par un code générique:
T x = whatever;
object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass
La méthode statique ne peut pas remplacer
class Vehicle{
static void park(int location){
System.out.println("Vehicle parking..");
}}
class Car extends Vehicle{
@Override //error
void park(int location) { //error
System.out.println("Car Parking..");
}}
La méthode privée ne peut pas remplacer
class Vehicle{
private void park(int location){
System.out.println("Vehicle parking..");
}
void callPark(){
park(100);
}}
class Car extends Vehicle{
//@Override
void park(int location) {
System.out.println("Car Parking..");
}}
class Demo {
public static void main(String[] args) {
Vehicle v1=new Car();
v1.callPark();
}}
La méthode finale ne peut pas remplacer
class Vehicle{
final void park(int location){
System.out.println("Vehicle parking..");
}}
class Car extends Vehicle{
//@Override
void park(int location) { //error
System.out.println("Car Parking..");
}}