2010-01-15 3 views
6

J'utilise Hibernate Validator et essayer de créer une petite classe util:Question sur les génériques Java - Classe <T> vs T?

public class DataRecordValidator<T> { 
    public void validate(Class<T> clazz, T validateMe) { 
     ClassValidator<T> validator = new ClassValidator<T>(clazz); 
     InvalidValue[] errors = validator.getInvalidValues(validateMe); 
     [...] 
    } 
} 

La question est, pourquoi dois-je fournir le paramètre Class<T> clazz lors de l'exécution new ClassValidator<T>(clazz)? Pourquoi ne pouvez-vous pas spécifier:

  1. T comme dans ClassValidator<T>(T)?
  2. validateMe.getClass() comme dans ClassValidator<T>(validateMe.getClass())

Je reçois des erreurs lorsque je tente de faire les deux options.

Modifier: Je comprends pourquoi # 1 ne fonctionne pas. Mais je ne comprends pas pourquoi # 2 ne fonctionne pas. Je reçois actuellement cette erreur aveC# 2:

cannot find symbol 
symbol : constructor ClassValidator(java.lang.Class<capture#279 of ? extends java.lang.Object>) 
location: class org.hibernate.validator.ClassValidator<T> 

Remarque: méthode API Hibernate est (here)

Répondre

1

Si la méthode validate est la votre, vous pouvez ignorer l'attribut Class en toute sécurité.

public void validate(T validateMe) { 
    ClassValidator<T> validator = 
      new ClassValidator<T>((Class<T>) validateMe.getClass()); 
    ... 
} 

Mais le constructeur ClassValidator nécessite un argument Class.

L'utilisation d'une dangereuse fonte n'est pas préféré, mais dans ce cas, il est en fait sûr si vous n'avez pas quelque chose comme ceci:

class A {..} 
class B extends A {..} 

new DataRecordValidator<A>.validate(new B()); 

Si vous pensez que vous aurez besoin de faire quelque chose comme ça, comprennent l'argument Class dans la méthode. Sinon, vous pouvez obtenir ClassCastException à l'exécution, mais c'est facilement débogable, même si ce n'est pas tout à fait l'idée derrière les génériques.

+0

Tristement ne fonctionne pas, voir ma réponse à la poste de @ Jherico. –

+0

J'ai fait une mise à jour, ça devrait fonctionner. – Bozho

+0

Merci, le '(classe )' était la clé! –

0

Parce que ClassValidator exige un objet de classe comme paramètre, une instance de la classe en question. Gardez à l'esprit que vous pourriez être en mesure de faire ce que vous essayez de faire avec ce code:

ClassValidator<? extends T> validator = new ClassValidator<? extends T>(validateMe.getClass()); 
+0

Merci. Pourquoi ne pouvez-vous pas utiliser 'validateMe.getClass()' ou 'T.class'? –

+0

J'ai pensé cela aussi ... mais j'ai cette erreur: 'ne peut pas trouver symbole' /' symbole: constructeur ClassValidator (java.lang.Class ) '/' emplacement: class org.hibernate.validator.ClassValidator ' –

+0

Regardez ma modification sur comment déclarer votre ClassValidator – Jherico

8

Parce que T est pas une valeur - il est juste une indication pour le compilateur. La JVM n'a aucune idée de la T. Vous pouvez utiliser des génériques uniquement en tant que type à des fins de vérification de type lors de la compilation.

+0

Merci. Pourquoi alors ne pouvez-vous pas utiliser 'validateMe.getClass()'? –

+1

Vous pouvez utiliser 'getClass()' sur n'importe quelle référence d'objet ... Juste coché, le compilateur est OK avec ça. –

+2

Vous pouvez utiliser 'validateMe.getClass() ', mais il y a des mises en garde: si' validateMe' est 'null', vous obtenez une exception' NullPointerException', qui peut être ou ne pas être ce que vous voulez. Et en utilisant le code actuel, vous pouvez passer une classe de base (par exemple, valider cette instance 'Employee' en utilisant les règles de sa classe de base' Person'). Si vous omettez le paramètre 'Class' qui n'est plus possible. –