Spec-Zone .ru
спецификации, руководства, описания, API
След: API Reflection
Урок: Элементы
Раздел: Поля
Поиск и устранение неисправностей
Домашняя страница > API Reflection > Элементы

Поиск и устранение неисправностей

Вот несколько типичных проблем, с которыми встречаются разработчики с объяснениями того, почему происходить и как разрешить их.

IllegalArgumentException из-за Необратимых Типов

FieldTrouble пример генерирует IllegalArgumentException. Field.setInt() вызывается, чтобы установить поле, которое имеет ссылочный тип Integer со значением типа примитива. В неотражательном эквиваленте Integer val = 42, компилятор преобразовал бы (или поле) тип примитива 42 к ссылочному типу как new Integer(42) так, чтобы его проверка типа приняла оператор. При использовании отражения введите проверку, только происходит во времени выполнения, таким образом, нет никакой возможности к полю значения.


import java.lang.reflect.Field;

public class FieldTrouble {
    public Integer val;

    public static void main(String... args) {
	FieldTrouble ft = new FieldTrouble();
	try {
	    Class<?> c = ft.getClass();
	    Field f = c.getDeclaredField("val");
  	    f.setInt(ft, 42);               // IllegalArgumentException

        // production code should handle these exceptions more gracefully
	} catch (NoSuchFieldException x) {
	    x.printStackTrace();
 	} catch (IllegalAccessException x) {
 	    x.printStackTrace();
	}
    }
}
$ java FieldTrouble
Exception in thread "main" java.lang.IllegalArgumentException: Can not set
  java.lang.Object field FieldTrouble.val to (long)42
        at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException
          (UnsafeFieldAccessorImpl.java:146)
        at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException
          (UnsafeFieldAccessorImpl.java:174)
        at sun.reflect.UnsafeObjectFieldAccessorImpl.setLong
          (UnsafeObjectFieldAccessorImpl.java:102)
        at java.lang.reflect.Field.setLong(Field.java:831)
        at FieldTrouble.main(FieldTrouble.java:11)

Чтобы устранить это исключение, проблематичная строка должна быть заменена следующим вызовом Field.set(Object obj, Object value):

f.set(ft, new Integer(43));

Подсказка: При использовании отражения, чтобы установить или получить поле, у компилятора нет возможности выполнить упаковку. Это может только преобразовать типы, которые связываются как описано спецификацией для Class.isAssignableFrom(). Пример, как ожидают, перестанет работать потому что isAssignableFrom() возвратится false в этом тесте, который может использоваться программно, чтобы проверить, возможно ли определенное преобразование:
Integer.class.isAssignableFrom(int.class) == false

Точно так же автоматическое преобразование от примитивного до ссылочного типа также невозможно в отражении.

int.class.isAssignableFrom(Integer.class) == false

NoSuchFieldException для Непубличных Полей

Проницательный читатель может заметить это если FieldSpy пример, показанный ранее, используется, чтобы получить информацию о непубличном поле, это перестанет работать:

$ java FieldSpy java.lang.String count
java.lang.NoSuchFieldException: count
        at java.lang.Class.getField(Class.java:1519)
        at FieldSpy.main(FieldSpy.java:12)

Подсказка: Class.getField() и Class.getFields() методы возвращают общедоступное задействованное поле (я) class, перечисления, или интерфейса, представленного Class объект. Получать все объявленные поля (но не наследованный) в Class, используйте Class.getDeclaredFields() метод.

IllegalAccessException, Изменяя Заключительные Поля

IllegalAccessException может быть брошен, если попытка предпринимается, чтобы получить или установить значение a private или иначе недоступное поле или установить значение a final поле (независимо от его модификаторов доступа).

FieldTroubleToo пример иллюстрирует тип трассировки стека, которая следует из попытки установить заключительное поле.


import java.lang.reflect.Field;

public class FieldTroubleToo {
    public final boolean b = true;

    public static void main(String... args) {
	FieldTroubleToo ft = new FieldTroubleToo();
	try {
	    Class<?> c = ft.getClass();
	    Field f = c.getDeclaredField("b");
// 	    f.setAccessible(true);  // solution
	    f.setBoolean(ft, Boolean.FALSE);   // IllegalAccessException

        // production code should handle these exceptions more gracefully
	} catch (NoSuchFieldException x) {
	    x.printStackTrace();
	} catch (IllegalArgumentException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	}
    }
}
$ java FieldTroubleToo
java.lang.IllegalAccessException: Can not set final boolean field
  FieldTroubleToo.b to (boolean)false
        at sun.reflect.UnsafeFieldAccessorImpl.
          throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:55)
        at sun.reflect.UnsafeFieldAccessorImpl.
          throwFinalFieldIllegalAccessException(UnsafeFieldAccessorImpl.java:63)
        at sun.reflect.UnsafeQualifiedBooleanFieldAccessorImpl.setBoolean
          (UnsafeQualifiedBooleanFieldAccessorImpl.java:78)
        at java.lang.reflect.Field.setBoolean(Field.java:686)
        at FieldTroubleToo.main(FieldTroubleToo.java:12)

Подсказка: ограничение доступа существует, который предотвращает final поля от того, чтобы быть установленным после инициализации class. Однако, Field как объявляют, расширяется AccessibleObject который обеспечивает возможность подавить эту проверку.

Если AccessibleObject.setAccessible() успешно выполняется, тогда последующие операции на этом значении поля не перестанут работать, делают к этой проблеме. У этого могут быть неожиданные побочные эффекты; например, иногда исходное значение будет продолжать использоваться некоторыми разделами приложения даже при том, что значение было изменено. AccessibleObject.setAccessible() только успешно выполнится, если работа будет позволена контекстом защиты.

Проблемы с примерами? Попытайтесь Компилировать и Выполнить Примеры: FAQ.
Жалобы? Поздравление? Предложения? Дайте нам свою обратную связь.

Предыдущая страница: Получение и Установка Значений полей
Следующая страница: Методы