2008-12-19 18 views
5

पर निर्धारित कक्षा में जाकर मेरे पास एक विधि fetchObjects(String) है जो Contract व्यावसायिक ऑब्जेक्ट्स की सरणी वापस करने की उम्मीद है। className पैरामीटर मुझे बताता है कि मुझे किस प्रकार की व्यावसायिक वस्तुएं वापस करनी चाहिए (बेशक यह इस कथित मामले में समझ में नहीं आता है क्योंकि मैंने पहले ही कहा है कि मैं Contract एस वापस कर दूंगा, लेकिन मूल रूप से यह स्थिति मेरे असली परिदृश्य में है)। इसलिए मुझे कहीं से प्रविष्टियों का सेट मिलता है और संग्रह की प्रविष्टियों की श्रेणी लोड होती है (जिस प्रकार का className द्वारा निर्दिष्ट किया गया है)।रन-टाइम

अब मुझे लौटने के लिए सरणी बनाने की आवश्यकता है, इसलिए मैं Set की toArray(T[]) विधि का उपयोग करता हूं। प्रतिबिंब का उपयोग करके, मैं खुद को एक खाली अनुबंध सरणी बना देता हूं। लेकिन, यह मुझे स्थिर प्रकार Object का एक मूल्य देता है! तो इसके बाद मुझे इसे उचित प्रकार पर डालना होगा, जो इस मामले में Contract[] है (नीचे दी गई सूची में "तारांकन-रेखांकित" भाग देखें)।

मेरे सवाल यह है: वहाँ एक रास्ता है, और कैसे, केवल className (या entriesType) के माध्यम से सूची, में के रूप में मैं कर Contract[] लिए डाली लेकिन सरणी तत्वों (Contract) के प्रकार का निर्धारण करने के लिए? दूसरे शब्दों में, मैं मूल रूप से इस तरह कास्टिंग करना चाहता हूं: (entriesType[]) valueWithStaticTypeObject, जहां प्रविष्टियों को classname पैरामीटर के माध्यम से निर्दिष्ट कक्षा द्वारा प्रतिस्थापित किया जा सकता है, यानी Contract

क्या यह किसी भी तरह से स्वाभाविक रूप से असंभव है, या यह किसी भी तरह से किया जा सकता है? शायद जेनेरिक का उपयोग कर?

package xx.testcode; 

import java.util.HashSet; 
import java.util.Set; 

class TypedArrayReflection { 

    public static void main(String[] args) { 
     try { 
      Contract[] contracts = fetchObjects("Contract"); 
      System.out.println(contracts.length); 
     } catch (ClassNotFoundException e) {} 
    } 

    static Contract[] fetchObjects(String className) throws ClassNotFoundException { 
     Class<?> entriesType = Class.forName("xx.testcode."+className); 
     Set<?> entries = ObjectManager.getEntrySet(className); 
     return entries.toArray( 
       (Contract[]) java.lang.reflect.Array.newInstance(
       /********/   entriesType, entries.size())); 
    } 
} 

class Contract { } // business object 

class ObjectManager { 
    static Set<?> getEntrySet(String className) { 
     if (className.equals("Contract")) 
      return new HashSet<Contract>(); 
     return null; // Error 
    } 
} 

धन्यवाद।


अद्यतन: प्रकार सुरक्षित तरीका toArray, CodeIdol से लिया का उपयोग करना, मैं अद्यतन मेरी fetchObjects इस प्रकार विधि:

static Contract[] fetchObjects(String className) throws ClassNotFoundException { 
    Class<?> entriesType = Class.forName("xx.testcode."+className); 
    Set<?> entries = ObjectManager.getEntrySet(className); 
    return toArray(entries, entriesType); // compile error 
    // -> "method not applicable for (Set<capture#3-of ?>, Class<capture#4-of ?>)" 
} 

public static <T> T[] toArray(Collection<T> c, Class<T> k) { 
    T[] a = (T[]) java.lang.reflect.Array.newInstance(k, c.size()); 
    int i = 0; 
    for (T x : c) 
     a[i++] = x; 
    return a; 
} 

क्या मैं उद्धृत संकलक त्रुटि से छुटकारा पाने के लिए क्या करना होगा टिप्पणी में? क्या मुझे अपने getEntrySet विधि के रिटर्न प्रकार में Set<Contract> निर्दिष्ट करना है ताकि यह काम कर सके? किसी भी पॉइंटर्स के लिए धन्यवाद।

+0

कक्षा प्रविष्टियों के दौरान आप कैसे संभालेंगे टाइप टाइप अनुबंध का उप-वर्ग नहीं है? –

+0

प्रविष्टियां टाइप * अनिवार्य रूप से अनुबंध का एक उप प्रकार नहीं है। यह पालतू, मित्र, हॉबी हो सकता है - जो कुछ भी आपके पास हो सकता है। मेरे उदाहरण मामले में ग्राहक के पास अनुबंधों का संग्रह होगा। –

उत्तर

7

आप कक्षा का उपयोग कक्षा के बजाय पैरामीटर के रूप में कर सकते हैं।

static <T extends Contract> T[] buildArray(Class<T> clazz){ 
    ArrayList<T> l=new ArrayList<T>(); 
    return l.toArray((T[]) java.lang.reflect.Array.newInstance(clazz, l.size())); 
    } 

संपादित करें: (के बाद पढ़ने के यांग टिप्पणी)

नहीं है, आप एक चर के मूल्य के साथ सामान्य प्रकार का उपयोग नहीं कर सकते हैं।

+0

यह बहुत प्रभावशाली है! हालांकि बात यह है कि मैं * कोड पैरामीटर क्लासनाम के आधार पर कंटेंट क्लास को कड़ी-कोडित नहीं करना चाहता हूं (बिजनेस ऑब्जेक्ट हाउस या पालतू भी हो सकता है)।दाएं वर्ग को वर्गनाम पैरामीटर से निर्धारित करने की आवश्यकता है। –

+0

चूंकि कॉलर को यह जानना होगा कि वह किस प्रकार की ऑब्जेक्ट की अपेक्षा करता है, वैसे भी, नाम के बजाए क्लास ऑब्जेक्ट में क्यों नहीं गुजरता है? मुझे यह नहीं मिला कि नाम का क्या फायदा है। –

+0

सीएफ। मिलहस के जवाब पर मेरी टिप्पणी। –

1

तो क्यों उपयोग नहीं

static <T> T[] buildArray(Class<T> clazz){ 
ArrayList<T> l=new ArrayList<T>(); 
return l.toArray((T[]) java.lang.reflect.Array.newInstance(clazz, l.size())); 
} 

नोट। ऊपर से कोड संशोधित।

+0

मुझे लगता है कि वह चाह सकता है कि जेनिक्स टाइपिंग/जेनेरिक/क्लास पैरामीटर के बिना "स्ट्रिंग क्लासनाम" के मान पर आधारित है। –

+0

बिल्कुल। वास्तविक परिदृश्य में, मुझे प्रकार का नाम प्राप्त करने के लिए प्रतिबिंब का उपयोग करने की आवश्यकता है, उदा। मुझे प्रतिबिंब से "अनुबंध" मिलता है और फिर कक्षा को इस नाम से लोड करता है। –

+3

आप संकलित समय पर अज्ञात किसी प्रकार के टाइपकास्ट नहीं कर सकते हैं। टाइपकास्टिंग एक संकलन-समय मुद्दा है। जेनिक्स टाइपकास्ट को पैरामीटर करने का एक तरीका है, ताकि कंपाइलर को कोड के एक हिस्से से दूसरे भाग में टाइप-सूचना प्रसारित करने दें। लेकिन यह अभी भी कंपाइलर के लिए जाना जाना चाहिए। –