Вопрос

Если я объявляю класс как поле:

Class fooClass;

Eclipse дает мне предупреждение:

Класс - это сырье. Ссылки на универсальный тип типа должны быть параметризованы

Что это значит на практике? И почему я призвал это сделать? Если я попрошу Eclipse для «быстрого исправления», это дает мне:

Class<?> fooClass;

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

Редактировать: почему класс универсальный? Не могли бы вы привести пример параметризации, то есть может быть правильное использование чего-то другого <?> ?

Редактировать: вау! Я не осознал глубину этого. Я также смотрел, как Java Puzzler, и он, безусловно, напугал меня о ловушках медведя. Так что я всегда буду использовать

Class<MyString> myStringClass = MyString.class;

скорее, чем

Class myStringClass = MyString.class;

(Но при использовании Java с первого дня я не заметил, когда урок стал общим);

Примечание: я принял @oxbow_lakes, так как это имеет смысл для меня, но это явно очень сложная область. Я бы побудил всех программистов использовать конкретный Class<MyString> скорее, чем Class. Отказ А также Class<?> намного безопаснее, чем Class.

Это было полезно?

Решение

Виды сырого и неограниченные подстановочные знаки

Ни один из предыдущих ответов действительно не обратился, почему вы должны предпочесть Class<?> над Class, Как на лице, первое, кажется, не предлагает больше информации, чем последний.

Причина в том, что сырой тип, т.е. Class, Предотвращает компилятор изготовить чеки общего типа. То есть, если вы используете сырье, ты подчиниться Тип-система. Отказ Например:

public void foo(Class<String> c) { System.out.println(c); }

Можно назвать призванные (оба скомпилированы а также бегать):

Class r = Integer.class
foo(r); //THIS IS OK (BUT SHOULDN'T BE)

Но не по:

Class<?> w = Integer.class
foo(w); //WILL NOT COMPILE (RIGHTLY SO!)

Всегда используя неращую форму, даже когда вы должны использовать ? Поскольку вы не можете знать, какой тип типа (или ограничен), вы разрешаете компилятору рассуждать о правильности вашей программы более полно, чем если вы использовали RAW Sype.


Почему вообще необработанные типы?

То Спецификация языка Java говорит:

Использование сырьевых типов разрешено только в качестве концессии к совместимости устаревшего кода

Вы всегда должны избегать их. Неограниченный подстановочный знак ? Вероятно, лучше всего описать в другом месте, но по существу означает «Это параметризовано на некотором типе, но я не знаю (или уход), что это». Отказ Это не то же самое, что сырье типов, которые являются мерзостью и не существуют на других языках с дженеранами, как Варенье.


Почему класс параметризован?

Ну, вот формат использования. Предположим, у меня есть какой-то сервисный интерфейс:

public interface FooService

И я хочу ввести ее реализацию, используя свойство системы для определения используемого класса.

Class<?> c = Class.forName(System.getProperty("foo.service"));

Я не знаю в этот момент, что мой класс имеет правильный тип:

//next line throws ClassCastException if c is not of a compatible type
Class<? extends FooService> f = c.asSubclass(FooService.class); 

Теперь я могу создать экземпляр FooService:

FooService s = f.newInstance(); //no cast

Другие советы

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

Ты прав. Но это может добавить значение:

Class<FooClass> fooClass;

или, если более подходит:

Class<? extends FooClass> fooClass;

или

Class<FooInterface> fooClass;

Как и в целом, вы можете улучшить безопасность типа, указав какой класса, который вы хотите переменную для удержания. Предупреждение против сырьевых типов просто предназначено для того, чтобы ловить кусочки кода, где этот потенциал не используется. Объявляя Class<?> Вы в основном говорите: «Это имел в виду держать любой класс ".

Потому что, поскольку JDK 5, Class теперь имеет параметризованный тип, который делает Class универсальный объект. Это необходимо (поскольку введение генеральных средств) для компилятора для проверки типа (в совокупности, конечно).

Class<?> означает «класс неизвестного», где ? это универсальность подстановочный знак. Отказ Это означает, что fooClass Тип Class<?> принимает а Class Чей тип совпадает с чем угодно.

Типичный пример:

Class<?> classUnknown = null;
classUnknown = ArrayList.class; //This compiles.

Вы можете, эффективно, предоставляют параметризованный тип, чтобы быть более конкретным, например:

Class<ArrayList> = ArrayList.class;

PS. Иметь в виду, что Class<List> listClass = ArrayList.class; не будет компитенна (даже несмотря на то, что ArrayList из списка), но (как отметил Марки Петерс на комментарии) Class<? extends List> listClass = ArrayList.class; делает компиляцию (благодаря подстановочным знаком).

Javadoc Сорт Класс делает некоторую идею о том, почему параметры типа существуют для этого класса:

T - тип класса, смоделированный этим Class объект. Например, тип String.class является Class<String>.Использовать Class<?> Если у класса моделируется неизвестен.

Использование этого параметра Thy Type не так очевидно, но беглый взгляд на исходный код класса, указывает, почему параметр типа иногда необходимо. Рассмотрим реализацию newInstance Метод:

    public T newInstance() 
        throws InstantiationException, IllegalAccessException
    {
    if (System.getSecurityManager() != null) {
        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader());
    }
    return newInstance0();
    }

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

Учитывая пример в вопросе, если экземпляр класса вместо этого объявлен как:

Class<String> fooClass;
Class<Integer> barClass;
String aString;

Тогда следующий невозможно иметь следующий код для компиляции:

aString = barClass.newInstance();

Короче говоря, если вы собираетесь работать с классовыми иерархиями, и вы хотите наложить строгие проверки времени компиляции, чтобы гарантировать, что ваш код не должен выполнять много instanceof Проверяет, то вам лучше указывать тип класса, который вы хотите использовать. Указание ? Позволяет всем типам, но были бы случаи, когда вам понадобится более конкретный.

Поскольку использование сырого типов вместо параметризованных типов имеет много ловушек.

Один из из них заключается в том, что если используется сырой тип, все дженерики на классе теряются. Даже те, которые определяли за метод.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top