[Java] जावा में कक्षा <टी> का उपयोग कैसे करें?


Answers

हम सभी जानते हैं कि " किसी भी वर्ग के सभी उदाहरण समान 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) {} साथ बुलाया जा सकता है

जेनिक्स का उपयोग करके इसे टाला जा सकता है।

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

अब टी क्या है ?? टी प्रकार पैरामीटर है (टाइप वैरिएबल भी कहा जाता है); कोण ब्रैकेट (<>) द्वारा सीमित, कक्षा के नाम का पालन करता है।
टी वर्ग फ़ाइल के लेखन के दौरान घोषित एक चर नाम (किसी भी नाम हो सकता है) की तरह एक प्रतीक है। बाद में टी को प्रतिस्थापित किया जाएगा
प्रारंभिकरण के दौरान वैध कक्षा का नाम ( 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; }
}

यहां टी को 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;
   }
}

लेकिन नीचे गलत है क्योंकि कक्षा-स्तर के प्रकार पैरामीटर के, वी, जेड, और वाई को स्थिर संदर्भ (यहां स्थिर विधि) में उपयोग नहीं किया जा सकता है।

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> से प्राप्त नहीं होगा। यह कक्षा स्तर टी के कारण उदाहरण के साथ बाध्य है।

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

Question

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

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




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

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



@ कियर हैग्लिन के उत्तर के बाद, जेएक्सबी अनारशेलिंग के लिए प्रलेखन में जेनेरिक विधियों का एक और उदाहरण देखा जा सकता है:

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 सामग्री पेड़ प्रकार का एक दस्तावेज़ वापस करने की अनुमति देता है।




बस एक और उदाहरण में फेंकने के लिए, कक्षा ( 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();
                }
            });
}



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

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