10
votes

Tapez la sécurité avec des génériques en Java

J'ai rencontré un comportement de génériques en Java que je ne peux pas comprendre complètement (avec mon arrière-plan .net). XXX

S'il vous plaît dites-moi pourquoi je ne reçois pas la classecast Obtenez, d'ailleurs, dans l'idée que je vois Temp comme string après la cession et la valeur de "crack !!!" . Aussi, comment pourrais-je avoir cette catégorie de ClasscastException? J'utilise JDK 1.7.0_07 sur Windows 7 x64.


0 commentaires

7 Réponses :


3
votes

Ceci est dû à Type-Erasure . Cela signifie que, dans Java, tous les génériques sont réduits à objet au moment de l'exécution. Vous avez donc lancé votre chaîne à objet qui est totalement fin. Et puisque Tostring est implémenté sur objet , à nouveau aucune exception.

Voici un lien sur Effacement de type

Le seul moyen de réellement obtenir vraiment le classcastexception est de passer une instance de Classe au type générique, puis faites MyClass.Isinstance (Arg ) et lancer une exception si false


2 commentaires

Est-ce vraiment le "seul moyen"? Nitegazer2003 a mentionné ce qui me frappe comme une approche plus propre, , car cela est clairement déclaré / visible / concis et ne pas encombrer le corps du code. Mais +1 pour "en Java, tous les génériques sont réduits à l'objet".


Ce que je veux dire par "le seul moyen", c'est qu'un générique n'a pas le type défini au moment de l'exécution. Par conséquent, si le comportement souhaité est de lancer une classeCastException, le type doit être explicitement fourni au générique en passant dans une instance de classe qui peut ensuite être utilisée pour vérifier le type. Votre commentaire sur numéro n'est valide que si c'est la condition. Il n'y a rien dans la mise en œuvre générique qui suggérerait qu'il ne devrait fonctionner que pour des instances de numéro .



16
votes

La raison pour laquelle vous n'obtenez pas une exception de casting de classe est que les génériques Java sont implémentées par l'effacement de type. Contrairement aux génériques de .NET qui nécessitaient des modifications importantes sur CLS, les génériques Java sont entièrement traitées dans la compilation. Au moment de l'exécution, la distribution à t code> est ignorée. Afin de vérifier le type à l'exécution, vous devez stocker class code> et utiliser ses méthodes pour vérifier le type d'un paramètre passé:

public class TestGeneric<T>
{
    private Class<T> genClass;
    public TestGeneric(Class<T> t) {genClass = t;}
    public void get (Object arg)
    {
        if (!genClass.isInstance(arg)) {
            throw new ClassCastException();
        }
        T temp = (T) arg;

        System.out.println(temp.toString());

        return;
    }
}

TestGeneric<Integer> tg = new TestGeneric<Integer>(Integer.class);
tg.get("Bang!!!"); // Now that's a real Bang!!!


2 commentaires

Avez-vous vraiment "besoin" ou y a-t-il une meilleure "meilleure pratique"? J'aime l'approche Nitegazer2003 mentionnée, , car cela est clairement déclaré / visible / concis et ne pas encombrer le corps du code. Il est également étroitement parallèle comment les génériques peuvent être restreints dans C #.


Bien que vous ayez répondu à sa question correctement, mais il est question de savoir comment utiliser le générique correctement et pourquoi avez-vous besoin d'un "retour" à la fin de rien? et ressemble à des voies plus compliquées que nécessaire. J'ai ajouté ma réponse de la façon dont vous devriez utiliser générique.



2
votes

Le type INTEGER a une méthode tostring . En fait, chaque objet a cette méthode afin que classcastexception ne se produise pas.

Vous n'avez appelé aucun chaîne -Pécurifique sur votre objet, aucune exception n'est donc produite.

La raison en est que, à l'exécution, vous ne verrez pas les paramètres de type BeaSe of Erasure de type .

Le point est qu'après la compilation de votre code, vous ne pourrez plus pouvoir voir les paramètres de type générique car ils sont effacés.

Il y a une autre question ici qui explique la classification de la classe exception: Explication < / p>

Dans ce code, vous pouvez voir que l'utilisateur a essayé de jeter explicitement à String pas sur un paramètre générique.

Vous pouvez donc appeler cela une lacune de Java par rapport à C #.


4 commentaires

-1: TOSTRING n'est pas automatiquement appelé lorsque vous lancez quelque chose, et cette distribution est l'autre direction de toute façon.


Je n'ai pas dit que cela est automatiquement appelé.


Après les modifications, votre réponse ne semble pas référencer le tout, ce qui est approprié, car il n'est pas pertinent. Si j'avais réellement évité, je l'aurais rétracté maintenant, mais cela semble que mon bowvote n'a pas pris.


"Vous n'avez appelé aucune méthode spécifique à la chaîne sur votre objet" mais en fait, il n'est pas possible d'appeler une méthode spécifique à la chaîne sur cette référence, car elle est de type t , un paramètre de type qui peut être n'importe quel type de référence.



8
votes

C'est parce que le type générique T n'a pas de limites définies, il est donc traité comme un objet. La coulée de quelque chose à t ne provoquera pas de clascastexception dans ce cas.

Toutefois, si votre définition de classe était CLASSE PUBLIC CLASSE TESTGÉRERIERRERIERRERIERRERIQUE , vous obtiendrez la classeCastException si vous avez passé une chaîne dans GET ().


1 commentaires

+1 Pour répondre à la question de l'OP sur la façon de recevoir une exception classique.



4
votes

Rappelez-vous toujours que les génériques de Java sont des entités de temps compilation. Cela n'a rien à faire au moment de l'exécution. Laissez-moi démo votre code OQN à vous.

Crack!!!
class java.lang.String


0 commentaires

7
votes

C'est un exercice instructif de penser à ce que le code non générique que le code générique est "effacé à" ressemble à: xxx


1 commentaires

Réponse géniale! Un exemple concret de quelle effacement fait effectivement.



4
votes

Si vous le faites de cette façon, vous n'avez même pas besoin de vérifier la classeCastException et que cela ne sera même pas capable de compiler. xxx


0 commentaires