Hoe Class<T> te gebruiken op Java?

Er is een goede discussie over Generics en wat ze echt doen achter de schermen bij deze vraag, dus we weten allemaal dat Vector<int[]>een vector is van integer-arrays en HashTable<String, Person>een tabel is waarvan de sleutels strings en waarden zijn Persons.
Wat me echter tegenvalt, is het gebruik van Class<>.

De java-klasse Classzou ook een sjabloonnaam moeten hebben (zo wordt mij verteld door de gele onderstreping in eclipse). Ik begrijp niet wat ik daar moet invullen. Het hele punt van het Classobject is wanneer je niet alle informatie over een object hebt, voor reflectie en dergelijke. Waarom moet ik specificeren welke klasse het Class-object zal bevatten? Ik weet het duidelijk niet, anders zou ik het Classobject niet gebruiken, ik zou het specifieke object gebruiken.


Antwoord 1, autoriteit 100%

Door de gegenereerde versie van class Class te gebruiken, kunt u onder andere dingen schrijven als

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

en dan kun je er zeker van zijn dat het Class-object dat je ontvangt Collectionuitbreidt, en een instantie van deze klasse zal (tenminste) een Collection zijn.


Antwoord 2, autoriteit 96%

Alles wat we weten is “Alle instanties van een willekeurige klasse delen hetzelfde java.lang.Class-object van dat type klasse

bijv.)

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

Dan is a.getClass() == b.getClass()waar.

Veronderstel nu

Teacher t = new Teacher();

zonder generieke geneesmiddelen is het onderstaande mogelijk.

Class studentClassRef = t.getClass();

Maar dit is nu verkeerd ..?

e.g) public void printStudentClassInfo(Class studentClassRef) {}kan worden aangeroepen met Teacher.class

Dit kan worden vermeden door generieke geneesmiddelen te gebruiken.

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

Wat is nu T?? T is typeparameters (ook wel typevariabelen genoemd); begrensd door punthaken (<>), volgt de klassenaam.

T is slechts een symbool, zoals een variabelenaam (kan elke naam zijn) die wordt gedeclareerd tijdens het schrijven van het klassenbestand. Later wordt die T vervangen door
geldige klassenaam tijdens initialisatie (HashMap<String> map = new HashMap<String>();)

bijv.) class name<T1, T2, ..., Tn>

Dus Class<T>vertegenwoordigt een klasseobject van het specifieke klassetype ‘T‘.

Veronderstel dat uw klassemethoden moeten werken met onbekende typeparameters zoals hieronder

/**
 * 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; }
}

Hier kan T worden gebruikt als Stringtyp als CarName

OR T kan worden gebruikt als Integertyp als modelNumber,

OR T kan worden gebruikt als Objecttype als geldige auto-instantie.

Hier is het bovenstaande de eenvoudige POJO die tijdens runtime anders kan worden gebruikt.

Collecties, bijv. Lijst, Set, Hashmap zijn de beste voorbeelden die zullen werken met verschillende objecten volgens de declaratie van T, maar zodra we T als String hebben gedeclareerd

bijv.) HashMap<String> map = new HashMap<String>();Dan accepteert het alleen String Class-instantieobjecten.

Algemene methoden

Generieke methoden zijn methoden die hun eigen typeparameters introduceren. Dit is vergelijkbaar met het declareren van een generiek type, maar het bereik van de type parameter is beperkt tot de methode waarin het wordt gedeclareerd. Statische en niet-statische generieke methoden zijn toegestaan, evenals generieke klassenconstructors.

De syntaxis voor een generieke methode bevat een typeparameter, tussen punthaken, en verschijnt vóór het retourtype van de methode. Voor generieke methoden moet het type parametersectie verschijnen vóór het retourtype van de methode.

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;
}

Hier <K, V, Z, Y>is de declaratie van typen die worden gebruikt in de methode-argumenten die vóór het retourtype moeten staan ​​dat hier booleanis.

In het onderstaande; typedeclaratie <T>is niet vereist op methodeniveau, omdat het al op klasseniveau is gedeclareerd.

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

Maar hieronder klopt niet, omdat de typeparameters K, V, Z en Y op klasseniveau niet kunnen worden gebruikt in een statische context (statische methode hier).

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());
    }
}

ANDERE GELDIGE SCENARIO’S ZIJN

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;
        }
    }

En tot slot heeft een statische methode altijd een expliciete <T>-declaratie nodig; Het zal niet afgeleid zijn van klasseniveau Class<T>. Dit komt omdat Klasse niveau T is gebonden aan bijvoorbeeld.

Lees ook Beperkingen op generieke geneesmiddelen

Wildcards en subtypen

typeargument voor een generieke methode


Antwoord 3, autoriteit 23%

Uit de Java-documentatie:

[…]
Meer verrassend, klasse Class is gegenereerd. Letterlijke klassen van klassen functioneren nu als typetokens en bieden zowel runtime- als compile-time-type-informatie. Dit maakt een stijl van statische fabrieken mogelijk, geïllustreerd door de getAnnotation-methode in de nieuwe AnnotatedElement-interface:

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

Dit is een generieke methode. Het leidt de waarde van zijn typeparameter T af uit zijn argument en retourneert een geschikte instantie van T, zoals geïllustreerd door het volgende fragment:

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

Voorafgaand aan generieke geneesmiddelen had u het resultaat naar Author moeten casten. Ook zou je geen manier hebben gehad om de compiler te laten controleren of de eigenlijke parameter een subklasse van Annotation vertegenwoordigde. […]

Nou, ik heb dit soort dingen nooit hoeven gebruiken. Iemand?


Antwoord 4, autoriteit 6%

Ik heb Class<T>nuttig gevonden wanneer ik zoekacties in het serviceregister maak. Bijv.

<T> T getService(Class<T> serviceClass)
{
    ...
}

Antwoord 5, autoriteit 3%

Zoals andere antwoorden aangeven, zijn er veel goede redenen waarom deze Classgeneriek is gemaakt. Het komt echter vaak voor dat u niet weet welk generieke type u moet gebruiken met Class<T>. In deze gevallen kunt u gewoon de gele eclipswaarschuwingen negeren of u kunt Class<?>gebruiken … Zo doe ik het 😉


Antwoord 6, autoriteit 3%

Na het antwoord van @Kire Haglin is een ander voorbeeld van generieke methoden te vinden in de documentatie voor 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();
}

Hierdoor kan unmarshaleen document van een willekeurig JAXB-inhoudsboomtype retourneren.


Antwoord 7, autoriteit 3%

In java betekent <T>de algemene klasse. Een generieke klasse is een klasse die kan werken met elk type gegevenstypeof met andere woorden, we kunnen zeggen dat het onafhankelijk is van het gegevenstype.

public class Shape<T> {
    // T stands for "Type"
    private T t;
    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

Waar Ttype betekent. Wanneer u nu een instantie van deze Shape-klasse maakt, moet u de compiler vertellen voor welk gegevenstype dit zal werken.

Voorbeeld:

Shape<Integer> s1 = new Shape();
Shape<String> s2 = new Shape();

Geheel getalis een type en Stringis ook een type.

<T>staat specifiek voor generiek type. Volgens Java Docs – Een generiek type is een generieke klasse of interface die is geparametriseerdover typen.


Antwoord 8

Je wilt vaak jokertekens gebruiken met Class. Bijvoorbeeld Class<? extends JComponent>uitbreidt, zou je kunnen specificeren dat de klasse een subklasse is van JComponent. Als u de instantie Classuit Class.forNamehebt opgehaald, kunt u Class.asSubclassgebruiken om de cast uit te voeren voordat u bijvoorbeeld probeert , maak een instantie.


Antwoord 9

Om nog een voorbeeld te noemen: de generieke versie van Class (Class<T>) stelt iemand in staat om generieke functies te schrijven, zoals die hieronder.

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();
                }
            });
}

Antwoord 10

In het begin is het verwarrend. Maar het helpt in de onderstaande situaties:

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.

Antwoord 11

Gebruik gewoon de beef-klasse:

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();
}

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Other episodes