2013-04-23 3 views
25

नहीं जानना, मेरे पास एक तरीका है जो कुछ ऑब्जेक्ट्स के साथ एक कस्टम List देता है। वे मुझे Object के रूप में वापस कर दिए जाते हैं। मुझे इन वस्तुओं से एक निश्चित क्षेत्र का मूल्य प्राप्त करने की आवश्यकता है, लेकिन मुझे ऑब्जेक्ट्स क्लास नहीं पता है।जावा प्रतिबिंब: किसी ऑब्जेक्ट से फ़ील्ड मान कैसे प्राप्त करें, इसकी कक्षा

क्या रिफ्लेसीन या किसी और तरह से ऐसा करने का कोई तरीका है?

+8

'Object.getClass()' - http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#getClass% 28% 2 9 –

उत्तर

38

एक साधारण मामला मानते हुए, जहां अपने क्षेत्र public है:

List list; // from your method 
for(Object x : list) { 
    Class<?> clazz = x.getClass(); 
    Field field = clazz.getField("fieldName"); //Note, this can throw an exception if the field doesn't exist. 
    Object fieldValue = field.get(x); 
} 

लेकिन यह बहुत बदसूरत है, और मैं कोशिश कैच के सभी बाहर छोड़ दिया, और मान्यताओं के एक नंबर (सार्वजनिक बनाता है क्षेत्र, प्रतिबिंब उपलब्ध, अच्छा सुरक्षा प्रबंधक)।

List<Foo> list; //From your method 
for(Foo foo:list) { 
    Object fieldValue = foo.fieldName; 
} 

या आप एक जावा 1.4 इंटरफेस जहां जेनरिक नहीं कर रहे 'लेने वाली रहे हैं:

आप एक List<Foo> वापस जाने के लिए अपनी पद्धति को बदल सकते हैं, तो यह क्योंकि इटरेटर तो आप जानकारी टाइप दे सकते हैं बहुत आसान हो जाता है टी उपलब्ध है, लेकिन आप वस्तुओं है कि सूची में होना चाहिए के प्रकार पता है ...

List list; 
for(Object x: list) { 
    if(x instanceof Foo) { 
     Object fieldValue = ((Foo)x).fieldName; 
    } 
} 

कोई प्रतिबिंब की जरूरत :)

+0

_ "अनुमान ... प्रतिबिंब उपलब्ध (एंड्रॉइड नहीं)" _ उम किसके अनुसार? एपीआई एलवीएल 1 http://developer.android.com/reference/java/lang/reflect/package-summary.html –

+0

के बाद से 'प्रतिबिंब' पैकेज एंड्रॉइड में उपलब्ध है, जाहिर है, मुझे एक साल पहले उस छोटे बिंदु पर गलती हुई थी। संपादित। मुख्य बिंदु बनी हुई है, कई जावा आधारित प्लेटफ़ॉर्म हैं जिन पर प्रतिबिंब एक कारण या किसी अन्य कारण के लिए उपलब्ध नहीं है। – Charlie

+0

@ चार्ली: लेकिन एसक्यूएल प्रश्नों से आने वाले ऑब्जेक्ट्स से कैसे निपटें हाइबरनेट में भाग गया। यदि आपके पास कई विधियां हैं, तो आपको प्रत्येक परिणाम के लिए कई क्लास प्रोटोटाइप बनाना होगा, है ना? क्या इसके लिए कोई आसान तरीका है ?? –

4

यदि आप जानते हैं कि फ़ील्ड किस वर्ग पर है तो आप प्रतिबिंब का उपयोग करके इसका उपयोग कर सकते हैं। यह उदाहरण (यह ग्रोवी में है लेकिन विधि कॉल समान हैं) कक्षा फू के लिए फ़ील्ड ऑब्जेक्ट प्राप्त करता है और ऑब्जेक्ट b ऑब्जेक्ट के लिए इसका मान प्राप्त करता है। यह दिखाता है कि आपको वस्तु के सटीक ठोस वर्ग की परवाह नहीं है, क्या मायने रखता है कि आप जानते हैं कि क्षेत्र किस वर्ग पर है और वह वर्ग या तो ठोस वर्ग या वस्तु का सुपरक्लास है।

groovy:000> class Foo { def stuff = "asdf"} 
===> true 
groovy:000> class Bar extends Foo {} 
===> true 
groovy:000> b = new Bar() 
===> [email protected] 
groovy:000> f = Foo.class.getDeclaredField('stuff') 
===> private java.lang.Object Foo.stuff 
groovy:000> f.getClass() 
===> class java.lang.reflect.Field 
groovy:000> f.setAccessible(true) 
===> null 
groovy:000> f.get(b) 
===> asdf 
+0

माना जाता है कि, यदि आप ग्रोवी का उपयोग कर रहे हैं, तो आखिरी बार मैंने इसका इस्तेमाल किया था (~ 1.7 युग) आप बस b.stuff और groovy कर सकते हैं सभी प्रतिबिंब और आपके लिए निजी तोड़ने ... (caviat के साथ यह जावा बीन विधियों getX के लिए सिंथेटिक चीनी भी करता है)। :) – Charlie

+0

@ चार्ली: हाँ, 'बी.स्टफ' इस के लिए ग्रोवी में पर्याप्त है। –

+0

यह बहुत अच्छा काम करता है और मेरे उपयोग के मामले के लिए बड़ी कुंजी सेट एक्सेस करने योग्य का उपयोग कर रही थी; यह एक कमजोर जावा पृष्ठभूमि से आ रहा है, लेकिन अन्य भाषाओं में मजबूत है। मैंने कुछ प्रतिबिंब तर्क को स्थानांतरित कर दिया और चीजें विफल होने लग गईं जब मैं सेट को सक्षम करने तक मूल्यों तक पहुंच नहीं पा रहा था। – Hazok

1

मैं मजबूत सामान्य प्रबंधन परिप्रेक्ष्य gly जावा जेनिक्स का उपयोग करने के लिए यह निर्दिष्ट करने के लिए अनुशंसा करें कि उस सूची में किस प्रकार का ऑब्जेक्ट है, यानी। List<Car>। यदि आपके पास कारें और ट्रकों हैं तो आप इस List<Vehicle> जैसे सामान्य सुपरक्लास/इंटरफ़ेस का उपयोग कर सकते हैं।

हालांकि, अगर आप वसंत के ReflectionUtils उपयोग कर सकते हैं क्षेत्रों सुलभ बनाने के लिए, भले ही वे नीचे runnable उदाहरण की तरह निजी हैं:

List<Object> list = new ArrayList<Object>(); 

list.add("some value"); 
list.add(3); 

for(Object obj : list) 
{ 
    Class<?> clazz = obj.getClass(); 

    Field field = org.springframework.util.ReflectionUtils.findField(clazz, "value"); 
    org.springframework.util.ReflectionUtils.makeAccessible(field); 

    System.out.println("value=" + field.get(obj)); 
} 

चल रहा है इस का उत्पादन किया है:

मूल्य = [ C @ 1b67f74
मूल्य = 3

+0

जेनेरिक मामला नहीं है, क्योंकि मेरे पास विधि कोड तक कोई पहुंच नहीं है। – svz

+0

मैंने जो उदाहरण पोस्ट किया है, उसे तब मदद करनी चाहिए। यह रनटाइम निरीक्षण के लिए भी निजी और अंतिम फ़ील्ड सुलभ बनाता है। – Erich

+0

"[सी @ 1b67f74" के बजाय मुझे "कुछ मूल्य" मान कैसे प्राप्त होगा? –

0

एक और मार्ग है, मैं अपने समर्थक में एक ही स्थिति मिल गया है अस्वीकृत। मैं इस तरह से

List<Object[]> list = HQL.list();

ऊपर हाइबरनेट क्वेरी भाषा में मुझे पता हल जो जगह मेरी वस्तुओं मुझे ऐसा क्या किया हैं क्या पर है:

for(Object[] obj : list){ 
String val = String.valueOf(obj[1]); 
int code =Integer.parseint(String.valueof(obj[0])); 
} 

इस तरह से आप के साथ मिश्रित वस्तुओं प्राप्त कर सकते हैं आसानी से, लेकिन आपको पहले से पता होना चाहिए कि आप किस स्थान पर जा रहे हैं या आप मूल्यों को प्रिंट करके जांच सकते हैं। बुरा अंग्रेज़ी मैं इस मदद

1
public abstract class Refl { 
    /** Use: Refl.<TargetClass>get(myObject,"x.y[0].z"); */ 
    public static<T> T get(Object obj, String fieldPath) { 
     return (T) getValue(obj, fieldPath); 
    } 
    public static Object getValue(Object obj, String fieldPath) { 
     String[] fieldNames = fieldPath.split("[\\.\\[\\]]"); 
     String success = ""; 
     Object res = obj; 
     for (String fieldName : fieldNames) { 
      if (fieldName.isEmpty()) continue; 
      int index = toIndex(fieldName); 
      if (index >= 0) { 
       try { 
        res = ((Object[])res)[index]; 
       } catch (ClassCastException cce) { 
        throw new RuntimeException("cannot cast "+res.getClass()+" object "+res+" to array, path:"+success, cce); 
       } catch (IndexOutOfBoundsException iobe) { 
        throw new RuntimeException("bad index "+index+", array size "+((Object[])res).length +" object "+res +", path:"+success, iobe); 
       } 
      } else { 
       Field field = getField(res.getClass(), fieldName); 
       field.setAccessible(true); 
       try { 
        res = field.get(res); 
       } catch (Exception ee) { 
        throw new RuntimeException("cannot get value of ["+fieldName+"] from "+res.getClass()+" object "+res +", path:"+success, ee); 
       } 
      } 
      success += fieldName + "."; 
     } 
     return res; 
    } 

    public static Field getField(Class<?> clazz, String fieldName) { 
     Class<?> tmpClass = clazz; 
     do { 
      try { 
       Field f = tmpClass.getDeclaredField(fieldName); 
       return f; 
      } catch (NoSuchFieldException e) { 
       tmpClass = tmpClass.getSuperclass(); 
      } 
     } while (tmpClass != null); 

     throw new RuntimeException("Field '" + fieldName + "' not found in class " + clazz); 
    } 

    private static int toIndex(String s) { 
     int res = -1; 
     if (s != null && s.length() > 0 && Character.isDigit(s.charAt(0))) { 
      try { 
       res = Integer.parseInt(s); 
       if (res < 0) { 
        res = -1; 
       } 
      } catch (Throwable t) { 
       res = -1; 
      } 
     } 
     return res; 
    } 
} 

यह प्राप्त करने में कठिनाई के खेतों और सरणी आइटम, जैसे का समर्थन करता है आशा के लिए खेद है:

System.out.println(""+Refl.getValue(b,"x.q[0].z.y")); 

वहाँ डॉट्स और ब्रेसिज़ के बीच कोई अंतर नहीं है, वे तो बस परिसीमक हैं, और खाली फ़ील्ड नाम अनदेखी कर रहे हैं:

System.out.println(""+Refl.getValue(b,"x.q[0].z.y[value]")); 
System.out.println(""+Refl.getValue(b,"x.q.1.y.z.value")); 
System.out.println(""+Refl.getValue(b,"x[q.1]y]z[value")); 
संबंधित मुद्दे