8
votes

Besoin de filtrer une liste à une sous-classe particulière à l'aide de génériques

J'ai une liste code> qui contient une superclasse (comme véhicule similaire) et je voudrais écrire une méthode qui renvoie les objets de cette liste qui sont des instances d'une certaine sous-classe (comme voiture) .

Jusqu'à présent, j'ai ceci, mais il génère un avertissement de compilateur de fonctionnement "non coché" typique: p> xxx pré>

p>

p>

List<Car> cars = getVehiclesOfType(Car.class);


2 commentaires

@Codemwnci, ​​@sblundy, oups, désolé. Avertissement standard "non coché". Question éditée pour ajouter ceci.


Je ne peux pas reproduire cet avertissement. Quel est le type de retour de GetveHicles ()?


8 Réponses :


3
votes

Que diriez-vous de cela?

public <T extends Vehicle> List<T> getVehiclesOfType(Class<T> type) {
    return Lists.newArrayList(Iterables.filter(getVehicles(), type));
}


1 commentaires

Oui, voir les modifications à la question originale. Celui que j'ai publié à l'origine était un avertissement caché de l'IDE, mais les messages du compilateur l'ont montré. (t) fait un avertissement différent et visible.



0
votes

Vous serez peut-être coincé avec l'ajout @suppresswarning ("non coché") à la méthode


1 commentaires

Je suis prêt à accepter cela comme la réponse, si vous pouvez expliquer pourquoi. Nous sommes instructions pour supprimer ou expliquer toute suppression d'avertissement.



6
votes

Vous obtenez un avertissement car il n'y a aucun moyen pour le compilateur (ou l'IDE) de savoir que la distribution est sûre, sans comprendre la signification de iSAssignAdFrom () . Mais isAssignableFrom () n'est pas une fonctionnalité de langue, c'est juste une méthode de la bibliothèque. En ce qui concerne le compilateur concerné, c'est la même chose que si vous l'avez dit xxx

Cependant, vous savez ce que isAssignablefrom () signifie, donc vous savez que c'est sûr que c'est sûr. C'est exactement le type de situation @suppresswarnings est destiné à.


5 commentaires

P.s. J'utiliserais Type.Isinstance () moi-même.


Donc, le compilateur donne à cet avertissement n'importe quel classe.cast () est utilisé?


Peut dépendre du compilateur. Avec Idea 9 et JDK 1.6 (expérimenter maintenant), je ne reçois pas un avertissement, même pour une utilisation totalement dangereuse qui conduit à une exception classique. Je suppose que la vérification de l'instance de est-ce que vous pouvez en faire un - pourrait éliminer l'avertissement, car il est alors connu au moment de la compilation pour être en sécurité. Mais je ne sais pas vraiment.


Comme je l'ai dit, l'EDI ne montre pas l'avertissement, mais quand je le compile. N'est pas le vôtre? Vous devriez avoir raison sur l'instance de la vérification mais qui n'est pas possible ici (objet de classe dynamique)


Je ne reçois pas l'avertissement de l'idée ni de Javac - qui dans le cas de Javac au moins est un peu curieux. Pourrait être une question de drapeaux compilateurs / préférences de l'IDE. (Utilisez-vous Eclipse? Il y a beaucoup de différences subtiles entre le compilateur Eclipse et Javac - généralement sans importance, mais vous les courez de temps en temps.) Peu importe, il ne me surprend pas que vous obtenez un AVERTISSEMENT ET SUPPRESSION SIMPLEMENT QUE SIMPLE QUE LA VOYAGE DROITE À FAIRE.



1
votes

Le problème est que le compilateur n'est pas assez intelligent de savoir que le véhicule est de "type" de classe. Ceci est une vérification d'exécution et le compilateur ne fait pas ce genre d'analyse. Il y a beaucoup de situations comme celle-ci. Par exemple, j'utilise si (vrai) retour; sortir d'une fonction tôt lors du débogage tout le temps. Si j'utilise juste retour, le compilateur se rend compte qu'il existe un code inaccessible, mais avec le conditionnel, le compilateur ne réalise pas qu'il est impossible d'entrer dans cette branche.

Considérez si vous remplacez votre conditionnel avec si (FALSE) {. Le code n'a aucune chance de jeter une exception mais contient toujours un casting dangereux.

Fondamentalement, le compilateur dit: "Je ne peux pas confirmer que c'est sûr, c'est donc à vous de vous assurer de savoir ce que vous faites." Votre code n'est pas cassé, il vous suffit de faire preuve de prudence.


0 commentaires

0
votes

Vous travaillez sur le véhicule, qui est une superclasse et que vous essayez de refuser la sous-classe de véhicule. C'est toujours un casting dangereux et vous rapportera un avertissement de compilateur.

Ainsi, alors que vous pouvez lancer de voiture à véhicule sans avertissement (car voiture prolonge le véhicule ), le compilateur n'a aucun moyen de savoir que La variable dactylographiée comme véhicule est en réalité une voiture.

En utilisant un casting (en utilisant (voiture) ou couler (..) ), vous racontez le compilateur que vous connaissez mieux. Le compilateur déteste les gens et maintiendra toujours un avertissement à vous :)


0 commentaires

0
votes

2 commentaires

Intéressant. C'est une bonne option à considérer, mais je ne suis pas fou de l'idée d'avoir à écrire la méthode de chaque type que j'ai. C'est pourquoi je voulais avoir une seule méthode. Mais j'apprécie le nouvel angle.


Vous n'avez vraiment que deux options que je le vois. Soit vous créez les méthodes d'assistant individuelles telles que mentionnées ci-dessus ou créez une seule méthode getvehiclesoftype dans votre superclasse de votre véhicule qui renvoie une liste et vous jetez le résultat à la liste appropriée Type - mais cela générerait la même chose Attention.



1
votes

2 choses:

J'aimerais savoir pourquoi j'étais recevoir un avertissement de compilateur sur le code d'origine, cependant.

1st: Regardez le code de classe: il cache la coulée pour vous. La coulée normalement à tout type arbitraire (T) devrait être un avertissement, mais la classe.Cast vérifie réellement et ignore l'avertissement du compilateur (non-sens). xxx

2e Cela étant dit: les avertissements des génériques sont la 1ère chose à désactiver. Avoir un mélange d'ancien code et maintenant ne vaut rien la peine d'avertir, ni je me soucierais. J'attends simplement de voir comment les génériques réduisent les génériques de Classcastexception et c'est probablement vrai en un seul cas: en utilisant ajouter addall (Met / PuTall)


0 commentaires

0
votes

Les réponses multiples à cette question affirment que l'avertissement est dû au fait que le compilateur ne peut pas Vérifier statiquement que la distribution ne peut pas échouer. Bien que le compilateur ne puisse vraiment pas vérifier cela, ce n'est aucune raison de donner un avertissement! Si le compilateur signalerait des avertissements pour toutes les moules qui ne peuvent pas être vérifiées de manière statique, qui bannie toutes les couts significatifs, car lorsqu'une distribution peut être vérifiée de manière statique, vous n'avez généralement pas besoin de faire la distribution en premier lieu. En d'autres termes, l'ensemble du point d'une opération de distribution est qu'il peut échouer au moment de l'exécution, qui est une situation parfaitement fine qui est traitée avec un Classcastexception . .

L'avertissement "non coché" d'avertissement d'autre part, se produit lorsque vous effectuez une distribution pour laquelle il existe des informations insuffisantes de type pour vérifier la distribution au moment de l'exécution . Cela peut se produire en raison de l'effacement des arguments de type au moment de l'exécution. Supposons que vous lanciez quelque chose de type statique Liste à Liste . Au moment de l'exécution, les objets de ces deux types ont simplement la classe arraylist ou linkedlist comme uniquement des informations de type d'exécution, sans arguments de type. Donc, le compilateur ne peut insérer aucun code qui vérifiera au moment de l'exécution que l'objet est en effet une liste de véhicule . Donc, le compilateur ne fait rien, mais soulève un avertissement "non coché".

Ceci est un avertissement utile, car vous pouvez rencontrer un problème lorsque vous commencez à utiliser le résultat de la distribution. Étant donné que le résultat a un type statique list , vous pouvez écrire du code qui traite des éléments de la liste sous forme de véhicule , sans avoir à écrire une distribution. Mais il y a encore un casting à l'exécution, et il échouera lorsque la liste s'avère contenir tout ce qui n'est pas un véhicule . Donc, vous pouvez obtenir un classcastexception à un point où vous ne l'avez pas attendu.

Le moyen sûr de gérer une telle conversion de la liste à list , est de itérer sur chacun des éléments, de les jeter à Véhicule (quelque chose que vous peut vérifier vérifier au moment de l'exécution et qui soulèvera un Classcastexception sur un point bien défini) et les ajoutez à une nouvelle liste. J'ai écrit un code générique pour faire précisément que dans Cette réponse .


0 commentaires