46

リフレクションによってオブジェクトから継承された保護フィールドにアクセスするにはどうすればよいですか?

4

11 に答える 11

65

問題が発生している可能性のある2つの問題-フィールドは通常はアクセスできない可能性があり(プライベート)、表示しているクラスではなく、階層のどこかにあります。

このようなものは、これらの問題でも機能します。

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);
  }
}
于 2009-04-09T18:08:19.557 に答える
10

FieldUtils.writeField(object, "fieldname", value, true)またはApache Commons lang3readField(object, "fieldname", true)から使用します。

于 2016-09-22T10:53:38.277 に答える
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));
    }
}
于 2010-04-08T01:12:53.933 に答える
6
field = myclass.getDeclaredField("myname");
field.setAccessible(true);
field.set(myinstance, newvalue);
于 2009-04-09T17:55:33.190 に答える
6

Spring を使用している場合、ReflectionTestUtilsは、最小限の労力でここで役立ついくつかの便利なツールを提供します。

たとえば、 であることがわかっている保護されたフィールド値を取得するには、次のようにしintます。

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

または、このフィールドの値を設定するには:

ReflectionTestUtils.setField(theClass, "theProtectedIntField", theIntValue);
于 2017-01-18T12:56:53.737 に答える
1

保護されたフィールドを取得するだけの場合

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

Eclipse Ctrl+Spaceを使用している場合、「.」を入力するとメソッドのリストが表示されます。オブジェクトの後

于 2016-09-16T15:52:23.690 に答える
1

これ以上ライブラリをドラッグしたくなかったので、自分に合った純粋なライブラリを作成しました。これは、jweyrich のメソッドの 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);
        }
    }

}
于 2012-12-12T06:25:11.680 に答える
0

おそらく、別のオブジェクトから、セットを持つ信頼できないコンテキストを意味していSecurityManagerますか? それは型システムを壊すので、できません。setAccessible信頼されたコンテキストから、型システムを打ち負かすために呼び出すことができます。理想的には、リフレクションを使用しないでください。

于 2009-04-09T17:57:01.470 に答える
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);
    }
}

Maurice's answer に記載されているように、アクセシビリティを変更する必要がある場合もあります。

于 2009-04-09T17:57:37.960 に答える
0

このクラスまたは任意のスーパークラスで任意の getter を実行する汎用ユーティリティ メソッド。

マリウスの答えから適応。

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

うまくいけば、それは誰かに役立ちます。

于 2013-10-18T22:37:17.610 に答える