2009-04-09 25 views
30

मैं प्रतिबिंब द्वारा एक वस्तु से इनहेरिट संरक्षित क्षेत्र का उपयोग कर सकते कैसे?जावा प्रतिबिंब - पहुँच संरक्षित क्षेत्र

+2

सवाल बेहतर होगा कि आप ने कहा:

int theIntValue = (int)ReflectionTestUtils.getField(theClass, "theProtectedIntField"); 

या वैकल्पिक रूप से इस फ़ील्ड का मान सेट करने के लिए क्या आप की कोशिश की (वास्तव में) और क्या (वास्तव में) हुआ। –

उत्तर

50

दो मुद्दों के साथ आपको समस्या हो सकती है - क्षेत्र सामान्य रूप से (निजी) तक पहुंच योग्य नहीं हो सकता है, और यह उस वर्ग में नहीं है जिसे आप देख रहे हैं, लेकिन कहीं पदानुक्रम ऊपर है।

कुछ इस तरह यहां तक ​​कि उन मुद्दों के साथ काम करेगा: वर्ग उदाहरण के सदस्यों तक पहुँचने के लिए प्रतिबिंब

public class SomeExample { 

    public static void main(String[] args) throws Exception{ 
    Object myObj = new SomeDerivedClass(1234); 
    Class myClass = myObj.getClass(); 
    Field myField = getField(myClass, "value"); 
    myField.setAccessible(true); //required if field is not normally accessible 
    System.out.println("value: " + myField.get(myObj)); 
    } 

    private static Field getField(Class clazz, String fieldName) 
     throws NoSuchFieldException { 
    try { 
     return clazz.getDeclaredField(fieldName); 
    } catch (NoSuchFieldException e) { 
     Class superClass = clazz.getSuperclass(); 
     if (superClass == null) { 
     throw e; 
     } else { 
     return getField(superClass, fieldName); 
     } 
    } 
    } 
} 

class SomeBaseClass { 
    private Integer value; 

    SomeBaseClass(Integer value) { 
    this.value = value; 
    } 
} 

class SomeDerivedClass extends SomeBaseClass { 
    SomeDerivedClass(Integer value) { 
    super(value); 
    } 
} 
+5

यदि कोई सुरक्षा प्रबंधक है, तो यह असफल हो जाएगा। आपको सेट करने के लिए कॉल को लपेटने की आवश्यकता है और एक PriviledgedAction में GetDeclaredField प्राप्त करें, और इसे java.security.AccessController.doPrivileged (...) – Varkhan

+0

से चलाएं मैं आपको अपने पूरे दिल से प्यार करता हूं –

+0

यह एंड्रॉइड पर काम नहीं करता है :(मेरी कक्षा पेड़ इस तरह दिखता है ए-> बी-> सी और सीआई के अंदर ए में घोषित संरक्षित क्षेत्र का मूल्य नहीं मिल सकता है नोट करें कि सभी तीन वर्ग अलग-अलग पैकेजों में हैं। किसी भी विचार को इसके आसपास कैसे जाना है? – Moonwalker

4
field = myclass.getDeclaredField("myname"); 
field.setAccessible(true); 
field.set(myinstance, newvalue); 
+1

यदि कोई सुरक्षा प्रबंधक है जो प्रासंगिक अनुमति को अवरुद्ध करता है तो यह काम नहीं कर सकता है। –

+0

getField (स्ट्रिंग नाम) केवल सार्वजनिक फ़ील्ड प्राप्त करें। – Moro

+0

@Moro: धन्यवाद, मैंने कोड –

0

आप शायद एक अलग वस्तु एक SecurityManager सेट के साथ किसी अविश्वसनीय संदर्भ से मतलब है? यही कारण है कि प्रकार प्रणाली टूट जाएगा, तो आप नहीं कर सकते। एक विश्वसनीय संदर्भ से, आप प्रकार प्रणाली को हराने के लिए setAccessible कॉल कर सकते हैं। आदर्श रूप में, प्रतिबिंब का उपयोग नहीं करते।

+0

घोषित नहीं किया था "आदर्श रूप से, प्रतिबिंब का उपयोग न करें।" क्यूं कर? ओपी विशेष रूप से प्रतिबिंब का उपयोग करने की कोशिश कर रहा है ... जबकि वह नहीं कहता है कि प्रतिबिंब के लिए कई वैध उपयोग क्यों हैं (विशेष रूप से टेस्ट कोड में)। –

+0

जबकि प्रतिबिंब के वैध उपयोग हैं, अधिकांश नहीं हैं। विशेष रूप से यदि आप जावा (1.0) भाषा पहुंच नियमों का सम्मान करने की विरासत क्षमता के आसपास रेंग रहे हैं, तो आपको शायद इसकी आवश्यकता नहीं है। –

+0

@ टॉम ... जब तक कि आप टेस्ट केस –

0

तुम कुछ की तरह कर सकता है ...

Class clazz = Class.forName("SuperclassObject"); 

Field fields[] = clazz.getDeclaredFields(); 

for (Field field : fields) { 
    if (field.getName().equals("fieldImLookingFor")) { 
     field.set...() // ... should be the type, eg. setDouble(12.34); 
    } 
} 

तुम भी रूप में मौरिस के जवाब में बताया गया है, पहुंच बदलने की जरूरत हो सकती है।

+0

इस वर्ग ऑब्जेक्ट द्वारा प्रतिनिधित्व कक्षा या इंटरफ़ेस द्वारा घोषित सभी फ़ील्ड को दर्शाते हुए फ़ील्ड ऑब्जेक्ट्स की एक सरणी देता है। यह सुपर क्लास – Moro

+0

के माध्यम से नहीं चला था क्या आप इस मुद्दे के साथ अधिक विशिष्ट हो सकते हैं? आप कह रहे हैं कि यह केवल आपके उप-वर्ग में फ़ील्ड प्राप्त कर चुका है? क्या आपने यह सुनिश्चित किया है कि क्लास.forनाम() विधि सुपरक्लास का नाम पारित किया जा रहा है, और मॉरीस ने सुझाव दिया है कि अभिगम्यता में संशोधन किया गया है? –

6

का प्रयोग करें, उन्हें सुलभ बनाने और उनके संबंधित मूल्यों की स्थापना की। बेशक आप प्रत्येक सदस्य आप बदलना चाहते हैं का नाम पता करना होगा, लेकिन मुझे लगता है कि कि एक समस्या नहीं होगी।

public class ReflectionUtil { 
    public static Field getField(Class clazz, String fieldName) throws NoSuchFieldException { 
     try { 
      return clazz.getDeclaredField(fieldName); 
     } catch (NoSuchFieldException e) { 
      Class superClass = clazz.getSuperclass(); 
      if (superClass == null) { 
       throw e; 
      } else { 
       return getField(superClass, fieldName); 
      } 
     } 
    } 
    public static void makeAccessible(Field field) { 
     if (!Modifier.isPublic(field.getModifiers()) || 
      !Modifier.isPublic(field.getDeclaringClass().getModifiers())) 
     { 
      field.setAccessible(true); 
     } 
    } 
} 

public class Application { 
    public static void main(String[] args) throws Exception { 
     KalaGameState obj = new KalaGameState(); 
     Field field = ReflectionUtil.getField(obj.getClass(), 'turn'); 
     ReflectionUtil.makeAccessible(field); 
     field.setInt(obj, 666); 
     System.out.println("turn is " + field.get(obj)); 
    } 
} 
1

मैं और पुस्तकालयों में खींचना नहीं चाहता था इसलिए मैंने एक शुद्ध व्यक्ति बनाया जो मेरे लिए काम करता था।

import java.lang.reflect.Field; 
import java.lang.reflect.Modifier; 
import java.util.Date; 
import java.util.Random; 
import java.util.UUID; 

public abstract class POJOFiller { 

    static final Random random = new Random(); 

    public static void fillObject(Object ob) { 
     Class<? extends Object> clazz = ob.getClass(); 

     do { 
      Field[] fields = clazz.getDeclaredFields(); 
      fillForFields(ob, fields); 

      if (clazz.getSuperclass() == null) { 
       return; 
      } 
      clazz = clazz.getSuperclass(); 

     } while (true); 

    } 

    private static void fillForFields(Object ob, Field[] fields) { 
     for (Field field : fields) { 
      field.setAccessible(true); 

      if(Modifier.isFinal(field.getModifiers())) { 
       continue; 
      } 

      try { 
       field.set(ob, generateRandomValue(field.getType())); 
      } catch (IllegalArgumentException | IllegalAccessException e) { 
       throw new IllegalStateException(e); 
      } 
     } 
    } 

    static Object generateRandomValue(Class<?> fieldType) { 
     if (fieldType.equals(String.class)) { 
      return UUID.randomUUID().toString(); 
     } else if (Date.class.isAssignableFrom(fieldType)) { 
      return new Date(System.currentTimeMillis()); 
     } else if (Number.class.isAssignableFrom(fieldType)) { 
      return random.nextInt(Byte.MAX_VALUE) + 1; 
     } else if (fieldType.equals(Integer.TYPE)) { 
      return random.nextInt(); 
     } else if (fieldType.equals(Long.TYPE)) { 
      return random.nextInt(); 
     } else if (Enum.class.isAssignableFrom(fieldType)) { 
      Object[] enumValues = fieldType.getEnumConstants(); 
      return enumValues[random.nextInt(enumValues.length)]; 
     } else if(fieldType.equals(Integer[].class)) { 
      return new Integer[] {random.nextInt(), random.nextInt()}; 
     } 
     else { 
      throw new IllegalArgumentException("Cannot generate for " + fieldType); 
     } 
    } 

} 
0

एक सामान्य उपयोगिता विधि इस या किसी भी सुपर क्लास में किसी भी गेटर को चलाने के लिए: यह jweyrich से तरीकों में से एक का एक विस्तार है।

Marius's उत्तर से अनुकूलित।

public static Object RunGetter(String fieldname, Object o){ 
    Object result = null; 
    boolean found = false; 
    //Search this and all superclasses: 
    for (Class<?> clas = o.getClass(); clas != null; clas = clas.getSuperclass()){ 
     if(found){ 
      break; 
     } 
     //Find the correct method: 
     for (Method method : clas.getDeclaredMethods()){ 
      if(found){ 
       break; 
      } 
      //Method found: 
      if ((method.getName().startsWith("get")) && (method.getName().length() == (fieldname.length() + 3))){ 
       if (method.getName().toLowerCase().endsWith(fieldname.toLowerCase())){        
        try{ 
         result = method.invoke(o); //Invoke Getter: 
         found = true; 
        } catch (IllegalAccessException | InvocationTargetException ex){ 
         Logger.getLogger("").log(Level.SEVERE, "Could not determine method: " + method.getName(), ex); 
        } 
       } 
      } 
     } 
    } 
    return result; 
} 

उम्मीद है कि यह किसी के लिए उपयोगी है।

1

तुम सिर्फ संरक्षित क्षेत्र मिल रहे हैं

Field protectedfield = Myclazz.class.getSuperclass().getDeclaredField("num"); 

आप ग्रहण Ctrl +अंतरिक्ष उपयोग कर रहे हैं जब आप लिखते हैं एक तरीकों की एक सूची सामने आ जाएंगे। "" ऑब्जेक्ट

3

FieldUtils.writeField(object, "fieldname", value, true) या readField(object, "fieldname", true)Apache Commons lang3 से उपयोग करें।

1

यदि वसंत का उपयोग करना, ReflectionTestUtils कुछ आसान उपकरण प्रदान करता है जो यहां न्यूनतम प्रयास के साथ मदद करते हैं।

उदाहरण के लिए, एक संरक्षित क्षेत्र मूल्य है कि जाना जाता है पाने के लिए एक int होने के लिए:

ReflectionTestUtils.setField(theClass, "theProtectedIntField", theIntValue); 
संबंधित मुद्दे