2009-02-26 28 views
32

बिना सी # में मैं वास्तव में यह कर सकते हैं:जेनेरिक विधि सामान्य तर्क

//This is C# 
static T SomeMethod<T>() where T:new() 
{ 
    Console.WriteLine("Typeof T: "+typeof(T)); 
    return new T(); 
} 

//And call the method here 
SomeMethod<SomeClassName>(); 

लेकिन किसी कारण मैं इसे जावा में काम करने के लिए नहीं मिल सकता है के लिए।

मैं जो चीज करना चाहता हूं वह सुपरक्लास पर एक स्थिर विधि बनाने के लिए है, इसलिए उप-वर्गों को एक्सएमएल में परिवर्तित किया जा सकता है।

//This is Java, but doesn't work 
public static T fromXml<T>(String xml) { 
    try { 
    JAXBContext context = JAXBContext.newInstance(T.class); 
    Unmarshaller um = context.createUnmarshaller(); 
    return (T)um.unmarshal(new StringReader(xml)); 
    } catch (JAXBException je) { 
    throw new RuntimeException("Error interpreting XML response", je); 
    } 
} 

//Also the call doesn't work... 
fromXml<SomeSubObject>("<xml/>"); 

उत्तर

48
public static <T> T fromXml(Class<T> clazz, String xml) { 

के रूप में कहा जाता है:

Thing thing = fromXml(Thing.class, xml); 

या अधिक स्पष्ट रूप से:

Thing thing = MyClass.<Thing>fromXml(Thing.class, xml); 

भ्रमित आप कंस्ट्रक्टर्स हो सकता है कि दोनों एक सामान्य प्रकार का निर्माण और एक सामान्य है और भी अधिक होना करने के लिए खुद पैरामीटर सिंटैक्स को याद नहीं किया जा सकता है और इसे क्रोध में कभी नहीं देखा है (वैसे भी आप एक स्थिर निर्माण विधि के साथ बेहतर तरीके से बंद हैं)।

कास्ट (T) असुरक्षित है, और आप टी.क्लास लिख नहीं सकते हैं। तो T.class को एक तर्क के रूप में शामिल करें (JAXBContext.newInstance करता है) और यदि गलत है तो प्रासंगिक अपवाद फेंक दें।

public static <T> T fromXml(Class<T> clazz, String xml) { 
    try { 
     JAXBContext context = JAXBContext.newInstance(clazz); 
     Unmarshaller um = context.createUnmarshaller(); 
     Object obj = um.unmarshal(new StringReader(xml)); 
     try { 
      return clazz.cast(obj); 
     } catch (ClassCastException exc) { 
      throw new RelevantException(
       "Expected class "+clazz+ 
        " but was "+obj.getClass() 
      ); 
     } 
    } catch (JAXBException exc) { 
     throw new RelevantException(
      "Error unmarshalling XML response", 
      exc 
     ); 
    } 
} 

मैं अगले JAXB के संस्करण का मानना ​​है (6u14 में?) JAXB कक्षा में बात इस तरह की लिए कुछ सुविधा तरीकों है।

+2

भी संकलन नहीं होगा ... आप T.class – pgras

+2

नहीं लिख सकते हैं मैं विधि में T.class बारे में मतलब नहीं था। मैंने एक Argumnet के रूप में कहा। और कॉलिंग फ़ंक्शन नहीं हो सकता है (या यह एक Argumnet के रूप में पारित हो सकता है)। –

+0

नया इंस्टेंस (टी। क्लास) एक प्रतिलिपि और पेस्ट था जिसे मैंने नहीं देखा था। अभी भी सवाल एक सामान्य विधि लिखने के बारे में प्रतीत होता है। –

5

जावा में, जेनेरिक केवल संकलित समय होते हैं, जो रन टाइम पर खो जाते हैं। इसलिए, यदि आपने इस तरह की एक विधि बुलाई है, तो JVM को यह जानने का कोई तरीका नहीं होगा कि T.class क्या था। इस के आसपास पाने के लिए सामान्य तरीके से एक वर्ग के उदाहरण वस्तु इस तरह, विधि करने के लिए एक पैरामीटर के रूप पारित करने के लिए है:

public static <T> T fromXml(Class<T> clazz, String xml) { 
    try { 
    JAXBContext context = JAXBContext.newInstance(clazz); 
    Unmarshaller um = context.createUnmarshaller(); 
    return (T)um.unmarshal(new StringReader(xml)); 
    } catch (JAXBException je) { 
    throw new RuntimeException("Error interpreting XML response", je); 
    } 
} 

fromXml(SomeSubObject.class, "<xml/>"); 
+0

पर काम करता है फिर भी एक सामान्य विधि लिखने का तरीका नहीं है। –

+0

लगभग। "स्थिर" के बाद सही होने की आवश्यकता है, न कि "fromxml" मुझे लगता है। – doekman

+0

आदर्श नहीं, नहीं। लेकिन अगर उसे रन टाइम पर प्रकार की जानकारी तक पहुंच की आवश्यकता होगी (JAXBContext.newInstance() को कॉल करने के लिए, उसे उस वर्ग या क्लास ऑब्जेक्ट की ऑब्जेक्ट की आवश्यकता होगी। – Avi

1

मुझे डर है कि तुम क्या करने के लिए बस जावा में काम नहीं करेगा कोशिश कर रहे हैं रहा हूँ। जेनेरिक प्रकारों के नए उदाहरण बनाने में सक्षम नहीं है उनमें से एक "जरूरी" विशेषताएं है जो .NET प्रदान की जाती है जबकि जावा बस गायब है। इससे पहले सुझाए गए लोगों की तरह "कामकाज" की ओर जाता है। ArrayList.toArray(T) को संदर्भ के रूप में देखें कि यह कैसे किया जा सकता है: अनिवार्य रूप से आपको उस ऑब्जेक्ट का संदर्भ पारित करना होगा जिसे आप बनाने की कोशिश कर रहे हैं ताकि आप जान सकें कि रनटाइम पर कौन सी कक्षा को तुरंत चालू करना है।

Set<Foo> foos = Collections.<Foo>emptySet(); 

Mockito के anyObject() विधि एक और उदाहरण है:

 

public <T> T[] toArray(T[] a) 
{ 
    if (a.length < size) 
    { 
     a = (T[]) java.lang.reflect.Array. 
     newInstance(a.getClass().getComponentType(), size); 
    } 
    System.arraycopy(elementData, 0, a, 0, size); 
    if (a.length > size) 
    { 
     a[size] = null; 
    } 
    return a; 
} 
 
2

तरीके जावा के Collections.emptySet() की तरह इस तरह के हस्ताक्षर है:

public static final <T> Set<T> emptySet() 

और इस तरह कहा जाता है यह ArrayList.toArray(T) से कोड है । मैं व्यक्तिगत रूप से वाक्यविन्यास को बहुत ही भयानक नहीं ढूंढता हूं। एक विधि तर्क के रूप में प्रकार को पास करना काम करता है लेकिन हमेशा kludgy महसूस किया। पैरामीटर प्रदान करते हुए emptySet() क्लीनर लगता है लेकिन यह हमेशा स्पष्ट नहीं होता है कि एक विधि एक प्रकार को निर्दिष्ट करने की अनुमति देती है।

1

वर्तमान उत्तर सुरक्षित है लेकिन तकनीकी रूप से पुराना है क्योंकि जावा 7 में और उससे परे आपको "क्लास क्लैज" तर्क की आवश्यकता नहीं है। प्रकार अपेक्षित रिटर्न प्रकार से अनुमानित है।आपको बस असुरक्षित कलाकारों के बारे में चेतावनी मिलती है।

public class Main { 

    private static class Dog { 
     public String toString() { return "dog"; } 
    } 

    private static class Cat { 
     public String toString() { return "cat"; } 
    } 

    public static void main(String[] args) { 
     Cat cat = parse("cat"); 
     Dog dog = parse("dog"); 
     System.out.println("the cat object is a " + cat); 
     System.out.println("the dog object is a " + dog); 
    } 

    private static Object untypedParse(String stringToParse) { 
     if(stringToParse.equals("dog")) { 
      return new Dog(); 
     } else if(stringToParse.equals("cat")) { 
      return new Cat(); 
     } else { 
      throw new RuntimeException("not expected"); 
     } 
    } 

    public static <T> T parse(String stringToParse) { 
     return (T)untypedParse(stringToParse); 
    } 

} 


~/test/generics$ javac Main.java 
Note: Main.java uses unchecked or unsafe operations. 
Note: Recompile with -Xlint:unchecked for details. 
~/test/generics$ java Main 
the cat object is a cat 
the dog object is a dog 
संबंधित मुद्दे