Java yansıması - setAccessible'ın etkisi (true)


106

Sınıflardaki alanların değerlerini dinamik olarak ayarlamak için bazı ek açıklamalar kullanıyorum. Herkese açık, korumalı veya özel olmasına bakılmaksızın bunu yapmak istediğim için setAccessible(true), set()yöntemi çağırmadan önce her seferinde Field nesnesini çağırıyorum . Sorum şu ki, setAccessible()çağrının sahanın kendisi üzerinde ne tür bir etkisi var?

Daha spesifik olarak, bunun özel bir alan ve bu kod çağrıları kümesi olduğunu söyleyin setAccessible(true). Kodda başka bir yer, aynı alanı yansıtma yoluyla almak olsaydı, alan zaten erişilebilir olacak mıydı? Veya getDeclaredFields()ve getDeclaredField()yöntemleri her seferinde bir Field nesnesinin yeni örneklerini mi döndürür?

Sanırım soruyu ifade etmenin başka bir yolu da ararsam, setAccessible(true)işim bittikten sonra onu orijinal değerine geri döndürmek ne kadar önemlidir?

Yanıtlar:


85

Sizinle , ie örneğinin setAccessible()davranışını değiştirir , ancak sınıfın gerçek alanını değiştirmezsiniz. İşte belgeler (alıntı):AccessibleObjectField

Bir değeri true, yansıtılan nesnenin, kullanıldığında Java dili erişim denetimi denetimlerini bastırması gerektiğini belirtir.

Ve çalıştırılabilir bir örnek:

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 ithalat beyanlarını kendiniz yazmanız gerekiyor. Umarım bunu nasıl yapacağını biliyorsundur.
Moritz Petersen

Bulunan sorun. NoSuchFieldException veya ebeveyni atmanız veya işlemeniz gerekir.
Philip Rego

Evet, bu sadece örnek kod. Demek istediğim, throws Exceptionaynı zamanda ele alır NoSuchFieldException, ancak daha ayrıntılı bir şekilde ele almak isteyebilirsiniz.
Moritz Petersen

İstisnayı şu alanda alıyorum: field1 = myClass.getClass (). GetDeclaredField ("theField"); yani derleme bile yapmıyor, yani setAccessible önemli değil mi?
kullanıcı2796104


3

Diğer posterlerin de belirttiği gibi setAccessible, yalnızca sizinjava.lang.reflect.Field , bu nedenle erişilebilirliği orijinal durumuna geri getirmek gerekli değildir.

Ancak...

Aramalarınızın field.setAccessible(true)kalıcı olmasını istiyorsanız, java.lang.Classve içindeki temel yöntemleri kullanmanız gerekir java.lang.reflect.Field. Yöntemleri bakan halk size göndermek kopyaları arasında Field, bu nedenle örneğin "unutur" Eğer böyle bir şey yapmak her zaman sonraclass.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();
        }
    }
}

Güncelleme : Bu uygulama Java 8 içindir, gelecekteki sürümler bunu bozan arka ucu değiştirir. Bu stratejiye gerçekten devam etmek istiyorsanız, aynı kavram hala geçerlidir.


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

}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.