जावा प्रतिबिंब - असफल का प्रभाव (सत्य)


105

मैं कक्षाओं में गतिशील रूप से मानों को सेट करने के लिए कुछ एनोटेशन का उपयोग कर रहा हूं। चूँकि मैं इसे सार्वजनिक, संरक्षित या निजी होने के बावजूद करना चाहता हूँ, इसलिए मैं विधि को setAccessible(true)कॉल करने से पहले हर बार फील्ड ऑब्जेक्ट पर कॉल कर रहा हूँ set()। मेरा सवाल यह है कि setAccessible()कॉल का क्षेत्र पर किस तरह का प्रभाव पड़ता है ?

अधिक विशेष रूप से, यह एक निजी क्षेत्र है और कोड कॉल का यह सेट है setAccessible(true)। यदि कोड में कुछ अन्य स्थान उसी क्षेत्र को प्रतिबिंब के माध्यम से पुनः प्राप्त करने के लिए था, तो क्या क्षेत्र पहले से ही सुलभ होगा? या क्या करता है getDeclaredFields()और getDeclaredField()तरीकों हर बार एक फील्ड के नए उदाहरणों लौट वस्तु?

मुझे लगता है कि प्रश्न को बताने का एक और तरीका है यदि मैं फोन करता हूं setAccessible(true), तो मेरे द्वारा किए जाने के बाद मूल मूल्य पर वापस सेट करना कितना महत्वपूर्ण है?

जवाबों:


85

setAccessible()आप के साथ व्यवहार बदल जाता है AccessibleObject, यानी Fieldउदाहरण, लेकिन वर्ग का वास्तविक क्षेत्र नहीं। यहाँ प्रलेखन (अंश) है:

एक मान trueइंगित करता है कि परावर्तित वस्तु का उपयोग होने पर जावा भाषा अभिगम नियंत्रण के लिए जांच को दबा देना चाहिए

और एक रननीय उदाहरण:

public class FieldAccessible {
    public static class MyClass {
        private String theField;
    }

    public static void main(String[] args) throws Exception {
        MyClass myClass = new MyClass();
        Field field1 = myClass.getClass().getDeclaredField("theField");
        field1.setAccessible(true);
        System.out.println(field1.get(myClass)); // no exception
        Field field2 = myClass.getClass().getDeclaredField("theField");
        System.out.println(field2.get(myClass)); // IllegalAccessException
    }

}

@PhilipRego को आपको आयात घोषणाएं स्वयं लिखनी होंगी। मुझे उम्मीद है कि आप जानते हैं कि यह कैसे करना है।
मोरित्ज़ पीटरसन

मुद्दा मिल गया। आपको NoSuchFieldException या पैरेंट को फेंकना या संभालना होगा।
फिलिप रीगो

हाँ, यह सिर्फ नमूना कोड है। मेरा मतलब है, throws Exceptionभी संभालता है NoSuchFieldException, लेकिन आप इसे अधिक विस्तृत तरीके से संभालना चाह सकते हैं।
मोरिट्ज़ पीटरसन

मुझे इस पर अपवाद मिल रहा है: फ़ील्ड field1 = myClass.getClass ()। GetDeclaredField ("theField"); इसलिए यह संकलन भी नहीं करता है, अर्थात सेट करने योग्य भी कोई फर्क नहीं पड़ेगा?
user2796104

32

getDeclaredFieldविधि एक नई वस्तु हर बार वापस जाने के लिए, वास्तव में, क्योंकि इस वस्तु परिवर्तनशील है है accessibleझंडा। इसलिए ध्वज को रीसेट करने की कोई आवश्यकता नहीं है। आप इस ब्लॉग पोस्ट में पूरी जानकारी पा सकते हैं ।


3

जैसा कि अन्य पोस्टरों ने संकेत दिया है, setAccessibleयह केवल आपके उस उदाहरण पर लागू होता है java.lang.reflect.Field, इसलिए इसकी मूल स्थिति तक पहुंच स्थापित करने की आवश्यकता नहीं है।

तथापि...

आप के लिए अपने कॉल चाहते हैं field.setAccessible(true)लगातार होने के लिए आप में अंतर्निहित तरीकों का उपयोग करने की जरूरत है java.lang.Classऔर java.lang.reflect.Field। सार्वजनिक सामना करने के तरीके आपको उदाहरण की प्रतियां भेजते हैं Field, इसलिए यह हर बार जब आप कुछ ऐसा करते हैं तो "भूल जाते हैं"class.getField(name)

import java.lang.reflect.*;
import sun.reflect.FieldAccessor;

public class Reflect {
    private static Method privateGetDeclaredFields;
    private static Method getFieldAccessor;

    public static Field[] fields(Class<?> clazz) throws Exception {
        return (Field[]) privateGetDeclaredFields.invoke(clazz, false);
    }

    public static <T> T get(Object instance, Field field) throws Exception {
        return ((FieldAccessor) getFieldAccessor.invoke(field, instance)).get(instance);
    }

    public static void set(Object instance, Field field, Object value) throws Exception {
        ((FieldAccessor) getFieldAccessor.invoke(field, instance)).set(instance, value);
    }

    static {
        try {
            // These are used to access the direct Field instances instead of the copies you normally get through #getDeclaredFields.
            privateGetDeclaredFields = Class.class.getDeclaredMethod("privateGetDeclaredFields", boolean.class);
            privateGetDeclaredFields.setAccessible(true);
            getFieldAccessor = Field.class.getDeclaredMethod("getFieldAccessor", Object.class);
            getFieldAccessor.setAccessible(true);
        } catch (Exception e) {
            // Should only occur if the internals change.
            e.printStackTrace();
        }
    }
}

अद्यतन : यह कार्यान्वयन जावा 8 के लिए है, भविष्य के संस्करण बैकएंड को बदलते हैं जो इसे तोड़ता है। एक ही अवधारणा अभी भी लागू होती है, हालांकि आपको वास्तव में इस रणनीति को जारी रखना चाहिए।


-1
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class PrivateVariableAcc {

    public static void main(String[] args) throws Exception {
        PrivateVarTest myClass = new PrivateVarTest();
        Field field1 = myClass.getClass().getDeclaredField("a");
        field1.setAccessible(true);
        System.out.println("This is access the private field-"
            + field1.get(myClass));
        Method mm = myClass.getClass().getDeclaredMethod("getA");
        mm.setAccessible(true);
        System.out.println("This is calling the private method-"
            + mm.invoke(myClass, null));
    }

}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.