Comment puis-je faire de la méthode de retour de type générique?
Considérer cet exemple (typique en programmation orientée objet, des livres):
J'ai un Animal
classe, où chaque Animal
peut avoir de nombreux amis.
Et les sous-classes comme Dog
, Duck
, Mouse
etc, qui ajoutent un comportement spécifique, comme bark()
, quack()
etc.
Voici la Animal
classe:
public class Animal {
private Map<String,Animal> friends = new HashMap<>();
public void addFriend(String name, Animal animal){
friends.put(name,animal);
}
public Animal callFriend(String name){
return friends.get(name);
}
}
Et voici un extrait de code avec beaucoup de typecasting:
Mouse jerry = new Mouse();
jerry.addFriend("spike", new Dog());
jerry.addFriend("quacker", new Duck());
((Dog) jerry.callFriend("spike")).bark();
((Duck) jerry.callFriend("quacker")).quack();
Est il possible que je peux utiliser des génériques pour le type de retour pour se débarrasser de la typecasting, de sorte que je peux dire
jerry.callFriend("spike").bark();
jerry.callFriend("quacker").quack();
Voici quelques code initial avec le type de retour transmis à la méthode comme un paramètre qui n'est jamais utilisé.
public<T extends Animal> T callFriend(String name, T unusedTypeObj){
return (T)friends.get(name);
}
Est-il un moyen de comprendre le type de retour à l'exécution sans le paramètre supplémentaire à l'aide de instanceof
? Ou au moins par le passage d'une catégorie du type, au lieu d'une instance fictive.
Je comprends les génériques sont pour moment de la compilation, la vérification de type, mais est-il une solution pour cela?
Vous devez vous connecter pour publier un commentaire.
Vous pouvez définir
callFriend
de cette façon:Ensuite appeler comme tel:
Ce code a l'avantage de ne pas générer des avertissements du compilateur. Bien sûr, cela est vraiment juste une version mise à jour de la conversion de la pré-générique de jours et de ne pas ajouter de sécurité supplémentaires.
Pas. Le compilateur ne peut pas savoir quel type
jerry.callFriend("spike")
serait de retour. Aussi, votre mise en œuvre vient se cache le casting de la méthode sans aucun autre type de sécurité. Considérez ceci:Dans ce cas précis, la création d'un résumé
talk()
méthode et primordial de façon adéquate dans les sous-classes vous servir beaucoup mieux:Vous pourriez la mettre en œuvre comme ceci:
(Oui, c'est légal, code; voir Java Génériques: type Générique défini comme type de retour seulement.)
Le type de retour sera déduit à partir de l'appelant. Toutefois, note le
@SuppressWarnings
annotation: qui vous dit que ce code n'est pas typesafe. Vous devez vérifier vous-même, ou vous pourriez obtenirClassCastExceptions
au moment de l'exécution.Malheureusement, la façon dont vous l'utilisez (sans affecter la valeur de retour d'une variable temporaire), le seul moyen de faire le bonheur du compilateur est de l'appeler comme ceci:
C'est peut-être un peu plus agréable que le casting, vous êtes probablement mieux de donner le
Animal
classe abstraitetalk()
méthode, comme David Schmitt dit.jerry.CallFriend<Dog>(...
qui, je pense, regarde mieux.java.util.Collections.emptyList()
fonction est mis en œuvre exactement comme ça, et sa javadoc annonce comme étant typesafe.Cette question est très similaire à l'Article 29 de dans Efficace Java - "Envisager de typesafe hétérogène des conteneurs." Laz de réponse est le plus proche de Bloch de la solution. Toutefois, les deux put et get devrait utiliser la Classe littéral pour la sécurité. Les signatures devient:
L'intérieur de ces deux méthodes, vous devriez vérifier que les paramètres sont corrects. Voir Efficace de Java et de la Classe javadoc pour plus d'info.
En outre, vous pouvez demander à la méthode retourne la valeur dans un type donné de cette façon
Plus d'exemples ici à Oracle Java documentation
Ici est la version plus simple:
Entièrement code de travail:
Comme vous l'avez dit en passant une classe serait OK, vous pouvez écrire ceci:
Et ensuite l'utiliser comme ceci:
Pas parfait, mais c'est à peu près aussi loin que vous obtenez avec Java génériques. Il y a un moyen de mettre en œuvre Typesafe Hétérogène Conteneurs (THC) à l'aide de Super Jetons de Type, mais qui a ses propres problèmes à nouveau.
Basé sur la même idée que le Super Type de Jetons, vous pouvez créer un typée id à utiliser à la place d'une chaîne de caractères:
Mais je pense que cela pourrait aller à l'encontre de l'objectif, puisque vous devez maintenant créer un nouvel id d'objets pour chaque chaîne et de le garder (ou de les reconstruire avec le bon type d'informations).
Mais vous pouvez maintenant utiliser la classe dans la façon dont vous vouliez à l'origine, sans le jette.
C'est juste cacher le type de paramètre à l'intérieur de l'identité, même si cela signifie que vous pouvez récupérer le type de l'identificateur plus tard si vous le souhaitez.
Vous auriez besoin pour mettre en œuvre la comparaison et le hachage des méthodes de TypedID trop si vous voulez être en mesure de comparer deux instances identiques d'une pièce d'identité.
"Est-il un moyen de comprendre le type de retour à l'exécution sans le paramètre supplémentaire à l'aide de instanceof?"
Comme une solution alternative vous pourriez utiliser le modèle Visiteur comme ça. Faire des Animaux abstrait et faire mettre en œuvre Visitables:
Visitables signifie simplement qu'un Animal de la mise en œuvre est disposée à accepter un visiteur:
Et un visiteur de la mise en œuvre est en mesure de visiter tous les sous-classes d'un animal:
Ainsi, par exemple, un Chien de la mise en œuvre ressemblerait alors à ceci:
Le truc c'est que tant que le Chien sait quel type il est, il peut provoquer pertinentes surchargé visite méthode du visiteur v en passant "ce" en tant que paramètre. D'autres sous-classes en œuvre accept() exactement de la même manière.
La classe qui veut appeler la sous-classe des méthodes spécifiques doit alors mettre en œuvre le Visiteur interface comme ceci:
Je sais que c'est beaucoup plus les interfaces et les méthodes que vous négocié, mais c'est une méthode standard pour obtenir une poignée sur chaque sous-type spécifique avec précisément zéro instanceof contrôles et zéro type de moulages. Et tout est fait dans un langage standard agnostique de la mode de sorte qu'il n'est pas juste pour Java, mais tout langage OO devrait fonctionner de la même.
Pas possible. Comment est la Carte censé savoir qui sous-classe de l'Animal qu'il va recevoir qu'une Chaîne de clé?
Le seul moyen ce serait possible si chaque Animal accepté qu'un seul type d'ami (alors qu'il pourrait être un paramètre de l'Animal de la classe), ou de la callFriend() la méthode a un paramètre de type. Mais on dirait vraiment que vous êtes à côté de la question de l'héritage: c'est que vous ne pouvez traiter les sous-classes de manière uniforme lors de l'utilisation exclusivement les méthodes de la superclasse.
J'ai écrit un article qui contient une preuve de concept, prise en charge de classes et une classe de test qui montre comment Super Jetons de Type peuvent être récupérées par vos cours au moment de l'exécution.
En un mot, il vous permet de déléguer à d'autres implémentations de la fonction réelle générique des paramètres transmis par l'appelant. Exemple:
TimeSeries<Double>
des délégués à l'intérieure privée de la classe qui utilisedouble[]
TimeSeries<OHLC>
des délégués à l'intérieure privée de la classe qui utiliseArrayList<OHLC>
Voir:
À l'aide de TypeTokens pour récupérer les paramètres génériques
Grâce
Richard Gomes - Blog
Il y a beaucoup de réponses ici, mais c'est l'approche que je prenais pour un Appium test où l'action sur un seul élément peut entraîner aller à différents états d'applications basées sur les paramètres de l'utilisateur. Alors qu'il ne suit pas les conventions de l'OP de l'exemple, j'espère que cela aide quelqu'un.
constructeur de type. Ce constructeur doit être le même entre toutes les classes.
Si vous ne voulez pas pour jeter les erreurs que vous pouvez attraper de la sorte:
Pas vraiment, parce que comme vous le dites, le compilateur sait seulement que callFriend() retourne un Animal, pas un Chien ou d'un Canard.
Pouvez-vous ne pas ajouter un résumé makeNoise() la méthode de l'Animal qui sera mis en œuvre comme une écorce ou de charlatan par ses sous-classes?
Ce que vous cherchez ici est l'abstraction. Code à l'aide d'interfaces de plus, et vous devez avoir à faire moins de casting.
L'exemple ci-dessous est en C#, mais le concept reste le même.
Je sais que c'est une chose complètement différente que celle qui l'a demandé. Une autre façon de résoudre ce serait réflexion. Je veux dire, ce n'est pas à prendre au profit des Génériques, mais il permet de simuler, en quelque sorte, le comportement que vous souhaitez effectuer (faire un aboiement de chien, faire un duck quack, etc.) sans prendre soin de conversion de type:
ce sujet
}
Je n'ai la suite dans ma lib kontraktor:
sous-classement:
au moins cela fonctionne à l'intérieur de la classe en cours et en ayant une forte référence typée. L'héritage Multiple fonctionne, mais devient vraiment difficile alors 🙂
Il y a une autre approche, vous pouvez préciser le type de retour lorsque vous remplacez une méthode. Dans chaque sous-classe que vous auriez à remplacer callFriend de retour cette sous-classe. Le coût serait les multiples déclarations de callFriend, mais vous pouvez isoler les parties communes d'une méthode appelée en interne. Cela semble beaucoup plus simple pour moi que les solutions mentionnées ci-dessus, et n'a pas besoin d'un argument supplémentaire pour déterminer le type de retour.
public int getValue(String name){}
est impossible de distinguer lespublic boolean getValue(String name){}
de la compilateurs point de vue. Vous devez soit modifier le type de paramètre ou ajouter/supprimer des paramètres pour la surcharge d'être reconnu. Peut-être que je suis juste un malentendu si vous...Vous pouvez retourner n'importe quel type et de recevoir directement comme. N'avez pas besoin de transtypage.
C'est le mieux si vous souhaitez personnaliser n'importe quel autre type de dossiers au lieu d'un vrai curseurs.
(Cursor) cursor
par exemple.cursor
être unCursor
, et retournera toujours unPerson
(ou null). L'utilisation de génériques supprime la vérification de ces contraintes, du code dangereux.