Вопрос-ответ

How to read the value of a private field from a different class in Java?

Как прочитать значение закрытого поля из другого класса в Java?

У меня плохо спроектированный класс от стороннего разработчика JAR и мне нужно получить доступ к одному из его закрытых полей. Например, зачем мне нужно выбирать закрытое поле, это обязательно?

class IWasDesignedPoorly {
private Hashtable stuffIWant;
}

IWasDesignedPoorly obj = ...;

Как я могу использовать отражение, чтобы получить значениеstuffIWant?

Переведено автоматически
Ответ 1

Чтобы получить доступ к закрытым полям, вам нужно получить их из объявленных полей класса, а затем сделать их доступными:

Field f = obj.getClass().getDeclaredField("stuffIWant"); //NoSuchFieldException
f.setAccessible(true);
Hashtable iWantThis = (Hashtable) f.get(obj); //IllegalAccessException

РЕДАКТИРОВАТЬ: как было прокомментировано аперкинсом, доступ к полю, установка его как доступного и извлечение значения могут вызвать Exceptions, хотя единственные проверенные исключения, о которых вам нужно помнить, прокомментированы выше.

NoSuchFieldException Будет выдано, если вы запросите поле по имени, которое не соответствует объявленному полю.

obj.getClass().getDeclaredField("misspelled"); //will throw NoSuchFieldException

IllegalAccessException Будет выдано, если поле недоступно (например, если оно закрыто и не было сделано доступным из-за пропуска f.setAccessible(true) строки.

RuntimeExceptionS, которые могут быть выданы, являются либо SecurityExceptions (если JVM SecurityManager не позволит вам изменить доступность поля), либо IllegalArgumentExceptions, если вы попытаетесь получить доступ к полю в объекте, отличном от типа класса поля:

f.get("BOB"); //will throw IllegalArgumentException, as String is of the wrong type
Ответ 2

Попробуйте FieldUtils из Apache commons-lang3:

FieldUtils.readField(object, fieldName, true);

P.S. На мой взгляд, отражение - это зло.

Ответ 3

Reflection isn't the only way to resolve your issue (which is to access the private functionality/behaviour of a class/component)

An alternative solution is to extract the class from the .jar, decompile it using (say) Jode or Jad, change the field (or add an accessor), and recompile it against the original .jar. Then put the new .class ahead of the .jar in the classpath, or reinsert it in the .jar. (the jar utility allows you to extract and reinsert to an existing .jar)

As noted below, this resolves the wider issue of accessing/changing private state rather than simply accessing/changing a field.

This requires the .jar not to be signed, of course.

Ответ 4

One other option that hasn't been mentioned yet: use Groovy. Groovy allows you to access private instance variables as a side effect of the design of the language. Whether or not you have a getter for the field, you can just use

def obj = new IWasDesignedPoorly()
def hashTable = obj.getStuffIWant()
java class reflection