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

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

Следующие примеры показывают типичные ошибки, с которыми можно встретиться когда размышляющий над классами.

Предупреждение компилятора: "Отметьте:... использует или опасные операции непроверенные"

Когда метод вызывается, типы значений аргументов проверяются и возможно преобразовываются. ClassWarning вызывает getMethod() вызвать типичное преобразование непроверенное, предупреждающее:


import java.lang.reflect.Method;

public class ClassWarning {
    void m() {
	try {
	    Class c = ClassWarning.class;
	    Method m = c.getMethod("m");  // warning

        // production code should handle this exception more gracefully
	} catch (NoSuchMethodException x) {
    	    x.printStackTrace();
    	}
    }
}
$ javac ClassWarning.java
Note: ClassWarning.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ javac -Xlint:unchecked ClassWarning.java
ClassWarning.java:6: warning: [unchecked] unchecked call to getMethod
  (String,Class<?>...) as a member of the raw type Class
Method m = c.getMethod("m");  // warning
                      ^
1 warning

Много методов библиотеки были retrofitted с универсальными объявлениями включая несколько в Class. С тех пор c объявляется как необработанный тип (не имеет никаких параметров типа), и соответствующий параметр getMethod() параметризованный тип, преобразование непроверенное происходит. Компилятор обязан генерировать предупреждение. (См. Спецификацию языка Java, Java SE 7 Выпусков, разделы Преобразование Преобразования и Вызова метода Непроверенное.)

Есть два возможных решения. Более предпочтительное это, чтобы изменить объявление c включать соответствующий универсальный тип. В этом случае объявление должно быть:

Class<?> c = warn.getClass();

Альтернативно, предупреждение могло быть явно подавлено, используя предопределенную аннотацию @SuppressWarnings предшествование проблематичному оператору.

Class c = ClassWarning.class;
@SuppressWarnings("unchecked")
Method m = c.getMethod("m");  
// warning gone

Подсказка: Как общий принцип, не должны быть проигнорированы предупреждения, поскольку они могут указать на присутствие ошибки. Параметризованные описания должны использоваться в качестве соответствующих. Если это не возможно (возможно, потому что приложение должно взаимодействовать с кодом поставщика библиотеки), аннотируйте незаконное использование строки @SuppressWarnings.

InstantiationException, когда Конструктор не Доступен

Class.newInstance() бросит InstantiationException если попытка предпринимается, чтобы создать новый экземпляр class, и конструктор нулевого параметра не видим. ClassTrouble пример иллюстрирует получающуюся трассировку стека.


class Cls {
    private Cls() {}
}

public class ClassTrouble {
    public static void main(String... args) {
	try {
	    Class<?> c = Class.forName("Cls");
	    c.newInstance();  // InstantiationException

        // production code should handle these exceptions more gracefully
	} catch (InstantiationException x) {
	    x.printStackTrace();
	} catch (IllegalAccessException x) {
	    x.printStackTrace();
	} catch (ClassNotFoundException x) {
	    x.printStackTrace();
	}
    }
}
$ java ClassTrouble
java.lang.IllegalAccessException: Class ClassTrouble can not access a member of
  class Cls with modifiers "private"
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
        at java.lang.Class.newInstance0(Class.java:349)
        at java.lang.Class.newInstance(Class.java:308)
        at ClassTrouble.main(ClassTrouble.java:9)

Class.newInstance() ведет себя очень как new ключевое слово и перестанет работать по тем же самым причинам new перестал бы работать. Типичное решение в отражении состоит в том, чтобы использовать в своих интересах java.lang.reflect.AccessibleObject class, который обеспечивает возможность подавить проверки управления доступом; однако, этот подход не будет работать потому что java.lang.Class не расширяется AccessibleObject. Единственное решение состоит в том, чтобы изменить код, чтобы использовать Constructor.newInstance() который действительно расширяется AccessibleObject.


Подсказка: Вообще, предпочтительно использовать Constructor.newInstance() по причинам, описанным в Создающем Новом разделе Экземпляров Класса в Задействованном уроке.

Дополнительные примеры потенциального использования задач Constructor.newInstance() может быть найден в Конструкторе, Диагностирующем раздел Задействованного урока.


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

Предыдущая страница: Обнаружение Элементов Класса
Следующая страница: Элементы