Comment utiliser la classe en Java?


Il y a une bonne discussion sur les génériques et ce qu'ils font vraiment dans les coulisses à cette question, donc nous savons tous que Vector<int[]> est un vecteur de tableaux entiers, et HashTable<String, Person>est une table dont les clés sont des chaînes et des valeurs Person s. Cependant, ce qui me touche, c'est l'utilisation de Class<>.

La classe java Class est censée également prendre un nom de modèle, (ou alors je suis dit par le soulignement jaune dans eclipse). Je ne comprends pas ce que je devrais mettre là-dedans. Le point de l'ensemble de l'objet Class est lorsque vous n'avez pas entièrement les informations sur un objet, pour la réflexion et autres. Pourquoi cela me fait-il spécifier quelle classe l'objet Class tiendra? Je ne sais clairement pas, ou je n'utiliserais pas l'objet Class, j'utiliserais celui spécifique.

Author: Community, 2009-01-20

10 answers

L'utilisation de la version générifiée de class Class vous permet, entre autres, d'écrire des choses comme

Class<? extends Collection> someCollectionClass = someMethod();

Et puis vous pouvez être sûr que l'objet de classe que vous recevez s'étend Collection, et une instance de cette classe sera (au moins) une Collection.

 110
Author: Yuval, 2014-10-20 10:31:25

Tout ce que nous savons, c'est que " Toutes les instances d'une classe quelconque partagent le même java.lang.Objet de classe de ce type de classe"

Par exemple)

Student a = new Student();
Student b = new Student();

Alors a.getClass() == b.getClass() est vrai.

Supposons Maintenant

Teacher t = new Teacher();

Sans génériques, ce qui suit est possible.

Class studentClassRef = t.getClass();

, Mais c'est faux maintenant ..?

Par exemple) public void printStudentClassInfo(Class studentClassRef) {} peut être appelé avec Teacher.class

Cela peut être évité en utilisant des génériques.

Class<Student> studentClassRef = t.getClass(); //Compilation error.

Maintenant, qu'est-ce que T ?? T est des paramètres de type (également appelés type variables); délimité par des crochets ( ), suit le nom de la classe.
T est juste un symbole, comme un nom de variable (peut être n'importe quel nom) déclaré lors de l'écriture du fichier de classe. Plus tard, T sera remplacé par
nom de classe valide lors de l'initialisation (HashMap<String> map = new HashMap<String>();)

Par exemple) class name<T1, T2, ..., Tn>

, Donc Class<T> représente un objet de classe de classe spécifique de type 'T'.

Supposons que vos méthodes de classe doivent fonctionner avec des paramètres de type inconnus comme ci-dessous

/**
 * Generic version of the Car class.
 * @param <T> the type of the value
 */
public class Car<T> {
    // T stands for "Type"
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

Ici, T peut être utilisé comme String type CarName

OU T peut être utilisé comme Integer type modelNumber,

OU T peut être utilisé comme Object type valide voiture instance.

Maintenant, voici le POJO simple qui peut être utilisé différemment lors de l'exécution.
Collections par exemple) List, Set, Hashmap sont les meilleurs exemples qui fonctionneront avec différents objets selon la déclaration de T, mais une fois que nous avons déclaré T comme chaîne
par exemple) HashMap<String> map = new HashMap<String>(); Ensuite, il n'acceptera que les objets d'instance de classe String.

Méthodes Génériques

Les méthodes génériques sont des méthodes qui introduisent leurs propres paramètres de type. Ceci est similaire à la déclaration d'un type générique, mais la portée du paramètre type est limitée à la méthode où il est déclaré. Les méthodes génériques statiques et non statiques sont autorisées, ainsi que les constructeurs de classes génériques.

La syntaxe d'une méthode générique comprend un paramètre de type, inside angle parenthèses, et apparaît avant le type de retour de la méthode. Pour les méthodes génériques, la section paramètre type doit apparaître avant le type de retour de la méthode.

 class Util {
    // Generic static method
    public static <K, V, Z, Y> boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}

 class Pair<K, V> {

    private K key;
    private V value;
}

Ici <K, V, Z, Y> est la déclaration des types utilisés dans les arguments de la méthode qui devrait avant le type de retour qui est boolean ici.

Dans ce qui suit; la déclaration de type <T> n'est pas requise au niveau de la méthode, car elle est déjà déclarée au niveau de la classe.

class MyClass<T> {
   private  T myMethod(T a){
       return  a;
   }
}

Mais ci-dessous est faux en tant que paramètres de type de niveau de classe K, V, Z et Y ne peuvent pas être utilisés dans un contexte statique (méthode statique ici).

class Util <K, V, Z, Y>{
    // Generic static method
    public static  boolean compare(Pair<K, V> p1, Pair<Z, Y> p2) {
        return p1.getKey().equals(p2.getKey()) &&
               p1.getValue().equals(p2.getValue());
    }
}

LES AUTRES SCÉNARIOS VALIDES SONT

class MyClass<T> {

        //Type declaration <T> already done at class level
        private  T myMethod(T a){
            return  a;
        }

        //<T> is overriding the T declared at Class level;
        //So There is no ClassCastException though a is not the type of T declared at MyClass<T>. 
        private <T> T myMethod1(Object a){
                return (T) a;
        }

        //Runtime ClassCastException will be thrown if a is not the type T (MyClass<T>).  
        private T myMethod1(Object a){
                return (T) a;
        }       

        // No ClassCastException        
        // MyClass<String> obj= new MyClass<String>();
        // obj.myMethod2(Integer.valueOf("1"));
        // Since type T is redefined at this method level.
        private <T> T myMethod2(T a){
            return  a;
        }

        // No ClassCastException for the below
        // MyClass<String> o= new MyClass<String>();
        // o.myMethod3(Integer.valueOf("1").getClass())
        // Since <T> is undefined within this method; 
        // And MyClass<T> don't have impact here
        private <T> T myMethod3(Class a){
            return (T) a;
        }

        // ClassCastException for o.myMethod3(Integer.valueOf("1").getClass())
        // Should be o.myMethod3(String.valueOf("1").getClass())
    private  T myMethod3(Class a){
        return (T) a;
    }


        // Class<T> a :: a is Class object of type T
        //<T> is overriding of class level type declaration; 
        private <T> Class<T> myMethod4(Class<T> a){
            return  a;
        }
    }

Et enfin la méthode statique a toujours besoin d'une déclaration explicite <T>; Elle ne dérivera pas du niveau de classe Class<T>. C'est à cause du niveau de classe T est lié à l'instance.

Lire Aussi Restrictions sur les médicaments Génériques

 136
Author: Kanagavelu Sugumar, 2016-09-15 14:18:59

De la documentation Java:

[...] Plus surprenant, la classe Class a été générifiée. Les littéraux de classe fonctionnent désormais comme des jetons de type, fournissant à la fois des informations de type à l'exécution et à la compilation. Cela active un style de fabriques statiques illustré par la méthode getAnnotation dans la nouvelle interface AnnotatedElement:

<T extends Annotation> T getAnnotation(Class<T> annotationType); 

C'est une méthode générique. Il déduit la valeur de son paramètre de type T de son argument, et renvoie une instance appropriée de T, comme illustré par le extrait suivant:

Author a = Othello.class.getAnnotation(Author.class);

Avant les génériques, vous auriez dû convertir le résultat en Auteur. De plus, vous n'auriez eu aucun moyen de faire vérifier par le compilateur que le paramètre réel représentait une sous-classe d'annotation. [...]

Eh bien, je n'ai jamais eu à utiliser ce genre de choses. N'importe qui?

 30
Author: raupach, 2011-11-03 23:26:09

J'ai trouvé class<T> utile lorsque je crée des recherches de registre de service. Par exemple

<T> T getService(Class<T> serviceClass)
{
    ...
}
 8
Author: Kire Haglin, 2009-01-20 21:52:48

Comme le soulignent d'autres réponses, il existe de nombreuses et bonnes raisons pour lesquelles ce class a été rendu générique. Cependant, il y a beaucoup de fois que vous n'avez aucun moyen de connaître le type générique à utiliser avec Class<T>. Dans ces cas, vous pouvez simplement ignorer les avertissements d'éclipse jaune ou utiliser Class<?> ... C'est comme ça que je le fais;)

 5
Author: bruno conde, 2009-01-20 17:53:39

Suite à la réponse de @Kire Haglin, un autre exemple de méthodes génériques peut être vu dans la documentation pour JAXB unmarshalling :

public <T> T unmarshal( Class<T> docClass, InputStream inputStream )
         throws JAXBException {
  String packageName = docClass.getPackage().getName();
  JAXBContext jc = JAXBContext.newInstance( packageName );
  Unmarshaller u = jc.createUnmarshaller();
  JAXBElement<T> doc = (JAXBElement<T>)u.unmarshal( inputStream );
  return doc.getValue();
}

Cela permet à unmarshal de renvoyer un document d'un type arbitraire d'arborescence de contenu JAXB.

 3
Author: Stew, 2012-11-07 16:29:53

Vous voulez souvent utiliser des caractères génériques avec Class. Par exemple, Class<? extends JComponent>, vous permettrait de spécifier que la classe est une sous-classe de JComponent. Si vous avez récupéré l'instance Class de Class.forName, vous pouvez utiliser Class.asSubclass pour effectuer la conversion avant d'essayer, par exemple, de construire une instance.

 2
Author: Tom Hawtin - tackline, 2009-01-20 17:47:13

Juste pour jeter un autre exemple, la version générique de Class (Class<T>) permet d'écrire des fonctions génériques telles que celle ci-dessous.

public static <T extends Enum<T>>Optional<T> optionalFromString(
        @NotNull Class<T> clazz,
        String name
) {
    return Optional<T> opt = Optional.ofNullable(name)
            .map(String::trim)
            .filter(StringUtils::isNotBlank)
            .map(String::toUpperCase)
            .flatMap(n -> {
                try {
                    return Optional.of(Enum.valueOf(clazz, n));
                } catch (Exception e) {
                    return Optional.empty();
                }
            });
}
 0
Author: zeronone, 2017-04-10 08:13:15

C'est déroutant au début. Mais cela aide dans les situations ci-dessous :

class SomeAction implements Action {
}

// Later in the code.
Class<Action> actionClass = Class.forName("SomeAction"); 
Action action = actionClass.newInstance();
// Notice you get an Action instance, there was no need to cast.
 -2
Author: fastcodejava, 2010-02-02 12:25:39

Utilisez simplement la classe de boeuf:

public <T> T beefmarshal( Class<beef> beefClass, InputBeef inputBeef )
     throws JAXBException {
     String packageName = docClass.getPackage().getBeef();
     JAXBContext beef = JAXBContext.newInstance( packageName );
     Unmarshaller u = beef.createBeef();
     JAXBElement<T> doc = (JAXBElement<T>)u.beefmarshal( inputBeef );
     return doc.getBeef();
}
 -5
Author: yaa, 2013-07-29 19:17:22