जावा में कक्षा <T> का उपयोग कैसे करें?


247

जेनरिक की एक अच्छी चर्चा है और वे वास्तव में इस सवाल पर पर्दे के पीछे क्या करते हैं , इसलिए हम सभी जानते हैं कि Vector<int[]>पूर्णांक सरणियों का एक वेक्टर है, और HashTable<String, Person>एक तालिका है जिसकी कुंजी तार और मान हैं Person। हालाँकि, जो स्टंप मुझे है, उसका उपयोग है Class<>

जावा क्लास Classको एक टेम्पलेट नाम भी लेना चाहिए, (या इसलिए मुझे ग्रहण में पीले रंग के आधार पर बताया जा रहा है)। मुझे समझ में नहीं आ रहा है कि मुझे वहाँ क्या करना चाहिए। Classऑब्जेक्ट का पूरा बिंदु तब होता है जब आपके पास किसी वस्तु के बारे में पूरी तरह से जानकारी नहीं होती है, प्रतिबिंब और इस तरह के लिए। यह मुझे क्यों निर्दिष्ट करता है कि कौन सा वर्ग किस Classवस्तु को धारण करेगा? मुझे स्पष्ट रूप से पता नहीं है, या मैं Classऑब्जेक्ट का उपयोग नहीं करूंगा , मैं विशिष्ट का उपयोग करूंगा।

जवाबों:


136

क्लास क्लास के जेनरेट किए गए संस्करण का उपयोग करना आपको अन्य चीजों के साथ, जैसे चीजों को लिखने की अनुमति देता है

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

और फिर आप यह सुनिश्चित कर सकते हैं कि आपके द्वारा प्राप्त की गई क्लास ऑब्जेक्ट फैली हुई है Collection, और इस वर्ग का एक उदाहरण (कम से कम) एक संग्रह होगा।


183

हम सभी जानते हैं कि " किसी भी वर्ग के सभी उदाहरण एक ही java.lang.Class को उस प्रकार के वर्ग के शेयर करते हैं "

जैसे)

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

तब a.getClass() == b.getClass()सच है।

अब मान लीजिए

Teacher t = new Teacher();

बिना जेनेरिक के संभव नहीं है।

Class studentClassRef = t.getClass();

लेकिन यह अब गलत है ..?

उदा) के public void printStudentClassInfo(Class studentClassRef) {}साथ बुलाया जा सकता हैTeacher.class

जेनरिक का इस्तेमाल करके इससे बचा जा सकता है।

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

अब T क्या है ?? टी टाइप पैरामीटर (जिसे टाइप वैरिएबल भी कहा जाता है); कोण कोष्ठक (<>) द्वारा सीमांकित, वर्ग नाम का अनुसरण करता है।
टी केवल एक प्रतीक है, वर्ग फ़ाइल के लेखन के दौरान घोषित एक चर नाम (किसी भी नाम हो सकता है) की तरह। बाद में टी को
आरंभिक ( HashMap<String> map = new HashMap<String>();) के दौरान मान्य वर्ग नाम से प्रतिस्थापित किया जाएगा।

जैसे) class name<T1, T2, ..., Tn>

तो Class<T>विशिष्ट वर्ग प्रकार ' T' के एक वर्ग वस्तु का प्रतिनिधित्व करता है ।

मान लें कि आपके वर्ग के तरीकों को नीचे की तरह अज्ञात प्रकार के मापदंडों के साथ काम करना है

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

यहाँ T का उपयोग CarName केString रूप में किया जा सकता है

या टी Integerको मॉडलनंबर के रूप में इस्तेमाल किया जा सकता है ,

या टी Objectको वैध कार उदाहरण के रूप में इस्तेमाल किया जा सकता है ।

अब यहाँ ऊपर सरल POJO है जिसका उपयोग रनटाइम के दौरान अलग-अलग तरीके से किया जा सकता है।
संग्रह उदाहरण) सूची, सेट, हैशमैप सबसे अच्छे उदाहरण हैं जो टी की घोषणा के अनुसार विभिन्न वस्तुओं के साथ काम करेंगे, लेकिन एक बार जब हमने टी को स्ट्रिंग के रूप में घोषित किया
) HashMap<String> map = new HashMap<String>();तो यह केवल स्ट्रिंग क्लास उदाहरण वस्तुओं को स्वीकार करेगा।

सामान्य तरीके

जेनेरिक विधियां ऐसी विधियां हैं जो अपने प्रकार के मापदंडों का परिचय देती हैं। यह एक सामान्य प्रकार की घोषणा करने के समान है, लेकिन प्रकार पैरामीटर्स का दायरा उस विधि तक सीमित है जहां यह घोषित किया गया है। स्थैतिक और गैर-स्थिर जेनेरिक विधियों की अनुमति है, साथ ही जेनेरिक वर्ग के निर्माणकर्ता भी।

जेनेरिक विधि के लिए सिंटैक्स में एक प्रकार का पैरामीटर होता है, कोण कोष्ठक के अंदर, और विधि के रिटर्न प्रकार से पहले प्रकट होता है। जेनेरिक तरीकों के लिए, विधि के रिटर्न प्रकार से पहले टाइप पैरामीटर सेक्शन दिखाई देना चाहिए।

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

यहां <K, V, Z, Y>विधि तर्कों में उपयोग किए जाने वाले प्रकारों की घोषणा है जो कि वापसी प्रकार से पहले होनी चाहिए जो booleanयहां है।

नीचे में; <T>विधि स्तर पर टाइप घोषणा की आवश्यकता नहीं है, क्योंकि यह पहले से ही कक्षा स्तर पर घोषित किया गया है।

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

लेकिन नीचे वर्ग के प्रकार के मापदंडों के रूप में गलत है K, V, Z, और Y का उपयोग स्थिर संदर्भ (स्थिर विधि) में नहीं किया जा सकता है।

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

अन्य वैध स्कोरर हैं

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

और अंत में स्थैतिक विधि को हमेशा स्पष्ट <T>घोषणा की आवश्यकता होती है ; यह वर्ग स्तर से व्युत्पन्न नहीं होगा Class<T>। इसका कारण है कि कक्षा स्तर T उदाहरण के लिए बाध्य है।

जेनरिक पर प्रतिबंध भी पढ़ें

वाइल्डकार्ड और सबटाइपिंग

जेनेरिक पद्धति के लिए तर्क टाइप करें


2
घिरे वाइल्डकार्ड पर मेरा जवाब stackoverflow.com/questions/1368166/...
Kanagavelu Sugumar

"क्लास <टी> विशिष्ट वर्ग प्रकार 'टी' के एक क्लास ऑब्जेक्ट का प्रतिनिधित्व करता है।" जो समझ में आता है। धन्यवाद ..
bynu022

यह उत्तर बहुत ही भ्रामक रूप से भ्रमित करता है जिस तरह से यह कक्षाओं में (स्कूल से) कक्षाओं (जावा में) के बारे में एक प्रश्न में उपयोग करता है। यह जानना मुश्किल है कि लेखक एक वाक्य से दूसरे वाक्य के बारे में क्या बात कर रहा है।
Echox

@ इकोक्स मुझे खेद है, यदि आप कोई विशिष्ट प्रश्न हैं, तो मैं इसे सुधार सकता हूं।
काणगावेलु सुगुमार


32

जावा प्रलेखन से:

[...] अधिक आश्चर्यजनक रूप से, क्लास क्लास को उत्पन्न किया गया है। क्लास के शाब्दिक अब टाइप-टोकन के रूप में कार्य करते हैं, रन-टाइम और संकलन-समय दोनों प्रकार की जानकारी प्रदान करते हैं। यह नए AnnotatedElement इंटरफ़ेस में getAnnotation विधि द्वारा छूट प्राप्त स्थिर कारखानों की एक शैली को सक्षम करता है:

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

यह एक सामान्य विधि है। यह अपने तर्क से अपने प्रकार के पैरामीटर टी के मूल्य को बढ़ाता है, और निम्नलिखित स्निपेट द्वारा सचित्र टी का एक उपयुक्त उदाहरण देता है:

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

जेनेरिक से पहले, आपको लेखक को परिणाम देना होगा। इसके अलावा आपके पास संकलक जांच करने का कोई तरीका नहीं होगा कि वास्तविक पैरामीटर एनोटेशन के उपवर्ग का प्रतिनिधित्व करता है। [...]

खैर, मुझे इस तरह के सामान का उपयोग कभी नहीं करना पड़ा। किसी को?


2
मुझे लगता है मेने कर दिया। एक ढांचा (प्रकार) मैंने आपके मॉड्यूल पर निर्भर सेवाओं के वर्गनाम को पारित करने के लिए आवश्यक काम किया। मैंने इसके ऊपर एक लेयर बनाया, जो क्लास ऑब्जेक्ट्स को ले गया, जैसा कि विकल्पों की मात्रा को सीमित करने के लिए। Class<? extends X>नोटेशन का उपयोग करके मुझे लगा कि मैं इसे केवल 'सेवा' प्रकारों तक सीमित कर सकता हूं। सिवाय कोई सामान्य 'सेवा' प्रकार नहीं था, इसलिए मैं केवल इसके साथ कर सकता था Class<?>। अफसोस।
fwielstra

9

class<T>सेवा रजिस्ट्री लुकअप बनाते समय मैंने उपयोगी पाया है। उदाहरण के लिए

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

5

जैसा कि अन्य उत्तर बताते हैं, कई और अच्छे कारण हैं कि इसे classसामान्य क्यों बनाया गया। हालाँकि कई बार ऐसा होता है कि आपके पास उपयोग करने के लिए सामान्य प्रकार जानने का कोई तरीका नहीं होता है Class<T>। इन मामलों में, आप बस पीले ग्रहण की चेतावनी को अनदेखा कर सकते हैं या आप इसका उपयोग कर सकते हैं Class<?>... यही कारण है कि मैं इसे कैसे करता हूं;)


@SuppressWarnings("unchecked")बचाव के लिए आता है! (हमेशा सावधान रहें कि इसे यथासंभव छोटे दायरे में लागू करें क्योंकि यह आपके कोड में संभावित समस्याओं को अस्पष्ट करता है।)
डोनल फेलो

4

@Kire Haglin के उत्तर पर, JAXB के लिए प्रलेखन में जेनरिक विधियों के एक और उदाहरण को देखा जा सकता है :

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

यह unmarshalएक मनमाने ढंग से JAXB कंटेंट ट्री टाइप के डॉक्यूमेंट को वापस करने की अनुमति देता है।


2

आप अक्सर वाइल्डकार्ड का उपयोग करना चाहते हैं Class। उदाहरण के लिए, Class<? extends JComponent>आपको यह निर्दिष्ट करने की अनुमति देगा कि वर्ग कुछ उपवर्ग है JComponent। यदि आपने इससे Classउदाहरण प्राप्त किया है Class.forName, तो आप उदाहरण प्रस्तुत Class.asSubclassकरने का प्रयास करने, कहने से पहले कलाकारों को करने के लिए उपयोग कर सकते हैं ।


2

जावा में <T>जेनेरिक क्लास का मतलब है। जेनेरिक क्लास एक ऐसा वर्ग है जो किसी भी प्रकार के डेटा प्रकार पर या दूसरे शब्दों में हम कह सकते हैं कि यह डेटा प्रकार स्वतंत्र है।

public class Shape<T> {
    // T stands for "Type"
    private T t;

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

जहां T का मतलब टाइप है। अब जब आप इस आकृति वर्ग का उदाहरण बनाते हैं, तो आपको संकलक को यह बताना होगा कि यह किस प्रकार का डेटा काम कर रहा है।

उदाहरण:

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

इंटेगर एक प्रकार है और स्ट्रिंग भी एक प्रकार है।

<T>विशेष रूप से सामान्य प्रकार के लिए खड़ा है। जावा डॉक्स के अनुसार - एक सामान्य प्रकार एक सामान्य वर्ग या इंटरफ़ेस है parameterized प्रकारों पर।


0

बस एक और उदाहरण में फेंकने के लिए, कक्षा का सामान्य संस्करण ( Class<T>) एक को नीचे दिए गए जैसे सामान्य कार्यों को लिखने की अनुमति देता है।

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

-2

यह शुरुआत में भ्रमित करने वाला है। लेकिन यह नीचे की स्थितियों में मदद करता है:

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.

4
क्या एक्शन ए = नई एक्शन () कहने का यह अविश्वसनीय रूप से जटिल तरीका नहीं है?
कार्ल

1
Action a = new Action() ? Actionमैं एक इंटरफेस है, यह है SomeActionहम कोशिश कर रहे हैं की एक उदाहरण मिलता है। हमारे पास केवल SomeActionरनटाइम पर उपलब्ध का नाम है।
फास्टकोडजवा

यह टाइपकास्टिंग पास नहीं करता है: जावा कंपाइलर के पास यह बताने का कोई तरीका नहीं है कि <code> Class.forName ("SomeAction") </ code> प्रकार का होगा <code> Class <Action> </ code>, क्योंकि यह केवल है। रनटाइम में जाना जाता है।
टोनियो

@tonio, ठीक है, इसलिए आपको शायद उस पहली पंक्ति को किसी तरह की कोशिश / पकड़ में लपेटना होगा। लेकिन यह मानते हुए कि कोई अपवाद नहीं है, दूसरी पंक्ति को काम करने की गारंटी है।
मेट्रिक्सफ्रॉग

2
क्या आप वास्तव में वर्णन कर रहे हैं कि SomeAction.class पैटर्न क्लास से मेल खाता है <? एक्सटेंड्स एक्शन> - अर्थात, यदि आपके पास मेथड एविएशन है (क्लास <; एक्सटेंड्स एक्शन> केलस), तो आप यूएशन (SomeAction.class) कह सकते हैं।
थॉमस एंड्रयूज

-5

बस गोमांस वर्ग का उपयोग करें:

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

4
यह वास्तव में प्रश्न का पूर्ण उत्तर प्रदान नहीं करता है। यदि आपको लगता है कि आपके पास जोड़ने के लिए कुछ है, तो इस उत्तर को संपादित करें।
मास्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.