Pertanyaan Refleksi Java - dampak dari setAccessible (true)


Saya menggunakan beberapa anotasi untuk menetapkan nilai bidang secara dinamis di kelas. Karena saya ingin melakukan ini terlepas dari apakah itu publik, dilindungi, atau pribadi, saya adalah seorang pemanggil setAccessible(true) pada objek Field setiap kali sebelum memanggil set() metode. Pertanyaan saya adalah apa dampaknya setAccessible() panggilan ada di lapangan itu sendiri?

Lebih spesifik lagi, katakan itu adalah bidang pribadi dan kumpulan panggilan kode ini setAccessible(true). Jika beberapa tempat lain dalam kode itu kemudian mengambil bidang yang sama melalui refleksi, apakah bidang itu sudah dapat diakses? Atau apakah itu getDeclaredFields() dan getDeclaredField() metode mengembalikan instance baru dari objek Field setiap kali?

Saya kira cara lain untuk menyatakan pertanyaan adalah jika saya menelepon setAccessible(true), seberapa pentingkah untuk mengembalikannya ke nilai asli setelah saya selesai?


75
2018-05-17 15:33


asal


Jawaban:


Dengan setAccessible() Anda mengubah perilaku AccessibleObject, yaitu Field Misalnya, tetapi bukan bidang sebenarnya dari kelas. Ini dia dokumentasi (kutipan):

Nilai dari true menunjukkan bahwa objek yang dipantulkan harus menekan pemeriksaan untuk kontrol akses bahasa Java ketika digunakan

Dan contoh yang dapat dijalankan:

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));
        Field field2 = myClass.getClass().getDeclaredField("theField");
        System.out.println(field2.get(myClass));
    }

}

56
2018-05-17 15:43



Itu getDeclaredField metode harus mengembalikan objek baru setiap kali, karena objek ini memiliki bisa berubah accessible bendera. Jadi tidak perlu me-reset bendera. Anda dapat menemukan detail lengkapnya posting blog ini.


27
2018-05-17 15:41



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));
    }

}

0
2017-11-23 09:45



Seperti yang ditunjukkan oleh poster lain, setAccessible hanya berlaku untuk contoh dari Anda java.lang.reflect.Field, sehingga pengaturan aksesibilitas kembali ke keadaan semula tidak diperlukan.

Namun...

Jika Anda ingin panggilan Anda field.setAccessible(true) untuk menjadi gigih Anda perlu menggunakan metode yang mendasarinya java.lang.Class dan java.lang.reflect.Field. Metode menghadap publik mengirim Anda salinan dari Field misalnya, jadi itu "lupa" setelah setiap kali Anda melakukan sesuatu seperti itu 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();
        }
    }
}

0
2018-03-12 00:42