Подтвердить что ты не робот

Установить значение частного поля с отражением

У меня есть 2 класса: Father и Child

public class Father implements Serializable, JSONInterface {

    private String a_field;

    //setter and getter here

}

public class Child extends Father {
    //empty class
}

С отражением я хочу установить a_field в Child класс:

Class<?> clazz = Class.forName("Child");
Object cc = clazz.newInstance();

Field f1 = cc.getClass().getField("a_field");
f1.set(cc, "reflecting on life");
String str1 = (String) f1.get(cc.getClass());
System.out.println("field: " + str1);

но у меня есть исключение:

Исключение в потоке "main" java.lang.NoSuchFieldException: a_field

Но если я попробую:

Child child = new Child();
child.setA_field("123");

он работает.

Использование метода setter У меня такая же проблема:

method = cc.getClass().getMethod("setA_field");
method.invoke(cc, new Object[] { "aaaaaaaaaaaaaa" });
4b9b3361

Ответ 1

Для доступа к частному полю вам нужно установить Field::setAccessible в значение true. Вы можете вытащить поле из суперкласса. Этот код работает:

Class<?> clazz = Child.class;
Object cc = clazz.newInstance();

Field f1 = cc.getClass().getSuperclass().getDeclaredField("a_field");
f1.setAccessible(true);
f1.set(cc, "reflecting on life");
String str1 = (String) f1.get(cc);
System.out.println("field: " + str1);

Ответ 2

Используя Apache commons-lang3:

FieldUtils.writeField(childInstance, "a_field", "Hello", true);

"Истина" заставляет его устанавливать, даже с "частным".

Ответ 3

Этот также может получить доступ к приватным полям, не делая ничего

import org.apache.commons.lang3.reflect.FieldUtils;
Object value = FieldUtils.readField(entity, fieldName, true);

Ответ 4

Вы можете использовать @Jailbreak от Manifold для прямого, типобезопасного отражения Java:

@Jailbreak Child child = new Child();
child.a_field = "123;

@Jailbreak разблокирует локальную переменную ребенка в компиляторе для прямого доступа ко всем членам в Child иерархии.

Точно так же вы можете использовать метод расширения jailbreak() для одноразового использования:

child.jailbreak().a_field = "123";

С помощью метода jailbreak() вы можете получить доступ к любому члену Child иерархии.

В обоих случаях компилятор разрешает доступ к полю для вас безопасно, как если бы это было открытое поле, тогда как Manifold генерирует эффективный код отражения для вас изнутри.

Узнайте больше о коллектор.

Ответ 5

В соответствии с Javadoc Class.getField (основное внимание):

Возвращает объект Field, который отражает указанное поле public member класса или интерфейса, представленного этим объектом класса.

Этот метод возвращает только публичные поля. Поскольку a_field является закрытым, он не будет найден.

Здесь рабочий код:

public class Main {

    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("Child");
        Object cc = clazz.newInstance();

        Field f1 = cc.getClass().getField("a_field");
        f1.set(cc, "reflecting on life");
        String str1 = (String) f1.get(cc);
        System.out.println("field: " + str1);
    }

}

class Father implements Serializable {
    public String a_field;
}

class Child extends Father {
//empty class
}

Обратите внимание, что я также изменил вашу строку String str1 = (String) f1.get(cc.getClass()); на String str1 = (String) f1.get(cc);, потому что вам нужно предоставить объект поля, а не класс.


Если вы хотите, чтобы ваше поле было приватным, вам нужно получить метод getter/setter и вызывать их. Код, который вы указали, не работает, потому что для получения метода вам также необходимо указать его аргументы, поэтому

cc.getClass().getMethod("setA_field");

должен быть

cc.getClass().getMethod("setA_field", String.class);

Здесь рабочий код:

public class Main {

    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("Child");
        Object cc = clazz.newInstance();
        cc.getClass().getMethod("setA_field", String.class).invoke(cc, "aaaaaaaaaaaaaa");
        String str1 = (String) cc.getClass().getMethod("getA_field").invoke(cc);
        System.out.println("field: " + str1);
    }

}

class Father implements Serializable {

    private String a_field;

    public String getA_field() {
        return a_field;
    }

    public void setA_field(String a_field) {
        this.a_field = a_field;
    }

}

class Child extends Father {
    //empty class
}