Обратите внимание, что причина существования необработанных типов заключается в обратной совместимости с Java 1.4 и более ранними версиями, у которых вообще не было обобщений.
Джеспер
Ответы:
745
Что такое сырой тип?
Спецификация языка Java определяет необработанный тип следующим образом:
Тип ссылки, который формируется путем взятия имени объявления универсального типа без сопровождающего списка аргументов типа.
Тип массива, тип элемента которого является необработанным типом.
Не- staticтипа члена исходного типа R, не унаследованный от суперкласса или суперинтерфейса R.
Вот пример для иллюстрации:
publicclassMyType<E>{classInner{}staticclassNested{}publicstaticvoid main(String[] args){MyType mt;// warning: MyType is a raw typeMyType.Inner inn;// warning: MyType.Inner is a raw typeMyType.Nested nest;// no warning: not parameterized typeMyType<Object> mt1;// no warning: type parameter givenMyType<?> mt2;// no warning: type parameter given (wildcard OK!)}}
Здесь MyType<E>- параметризованный тип ( JLS 4.5 ). Обычно в разговорной речи называют этот тип просто MyTypeдля краткости, но формально это имя MyType<E>.
mtимеет необработанный тип (и генерирует предупреждение о компиляции) по первому пункту в приведенном выше определении; innтакже имеет необработанный тип по третьему пункту.
MyType.Nestedне параметризованный тип, хотя это тип члена параметризованного типа MyType<E>, потому что это static.
mt1и mt2оба объявлены с фактическими параметрами типа, поэтому они не являются необработанными типами.
Что такого особенного в необработанных типах?
По сути, необработанные типы ведут себя так же, как и до появления дженериков. То есть, следующее является полностью законным во время компиляции.
List names =newArrayList();// warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE);// not a compilation error!
Приведенный выше код работает просто отлично, но предположим, что у вас также есть следующее:
for(Object o : names){String name =(String) o;System.out.println(name);}// throws ClassCastException!// java.lang.Boolean cannot be cast to java.lang.String
Теперь мы сталкиваемся с проблемами во время выполнения, потому что namesсодержит что-то, что не является instanceof String.
Предположительно, если вы хотите namesсодержать только String, возможно , вы все еще могли бы использовать необработанный тип и вручную проверять каждыйadd сам, а затем вручную приводить к Stringкаждому элементу из names. Еще лучше , хотя НЕ использовать необработанный тип и позволить компилятору сделать всю работу за вас , используя всю мощь Java-дженериков.
Конечно, если вы НЕ хотите , namesчтобы позволить Boolean, то вы можете объявить его как List<Object> namesи приведенный выше код будет компилироваться.
Чем необработанный тип отличается от использования в <Object>качестве параметров типа?
Ниже приводится цитата из Effective Java 2nd Edition, пункт 23. Не используйте необработанные типы в новом коде :
В чем разница между необработанным типом Listи параметризованным типом List<Object>? Грубо говоря, первый отказался от проверки универсального типа, в то время как последний явно сказал компилятору, что он способен содержать объекты любого типа. Хотя вы можете передавать List<String>параметр типа List, вы не можете передать его параметру типа List<Object>. Существуют правила подтипов для обобщений, и List<String>это подтип необработанного типа List, но не параметризованного типа List<Object>. Как следствие, вы теряете безопасность типов, если вы используете сырой тип как List, но не если вы используете параметризованный тип какList<Object> .
Чтобы проиллюстрировать это, рассмотрим следующий метод, который принимает List<Object>и добавляет a new Object().
Если бы вы объявили, appendNewObjectчто в Listкачестве параметра принимается необработанный тип , он скомпилируется, и поэтому вы потеряете безопасность типов, которую вы получаете от обобщений.
Чем необработанный тип отличается от использования <?>в качестве параметра типа?
List<Object>и List<String>т. д. все List<?>, так что может быть заманчиво просто сказать, что они просто Listвместо. Тем не менее, есть существенное отличие: поскольку a List<E>определяет только add(E), вы не можете добавить любой произвольный объект в a List<?>. С другой стороны, поскольку необработанный тип Listне имеет безопасности типов, вы можете получить addчто угодно List.
Рассмотрим следующий вариант предыдущего фрагмента:
staticvoid appendNewObject(List<?> list){
list.add(newObject());// compilation error!}//...List<String> names =newArrayList<String>();
appendNewObject(names);// this part is fine!
Компилятор прекрасно защитил вас от возможного нарушения неизменности типов List<?>! Если бы вы объявили параметр как необработанный тип List list, то код скомпилировался бы, и вы нарушили бы инвариант типа List<String> names.
Необработанный тип - это стирание этого типа.
Вернуться к JLS 4.8:
В качестве типа можно использовать стирание параметризованного типа или стирание типа массива, тип элемента которого является параметризованным типом. Такой тип называется необработанным типом .
[...]
Суперклассы (соответственно, суперинтерфейсы) необработанного типа являются стиранием суперклассов (суперинтерфейсов) любой из параметризаций универсального типа.
Тип конструктора, метода экземпляра или неполя staticполя необработанного типа, Cкоторый не унаследован от его суперклассов или суперинтерфейсов, является необработанным типом, который соответствует удалению его типа в общем объявлении, соответствующем C.
Проще говоря, когда используются сырой типа, конструкторы, методы экземпляра и не- staticполей также удаляется .
Стирание типа также отображает сигнатуру конструктора или метода в сигнатуру, которая не имеет параметризованных типов или переменных типа. Стирание сигнатуры конструктора или метода s- это сигнатура, состоящая из того же имени, что sи стирание всех типов формальных параметров, приведенных в s.
Возвращаемый тип метода и параметры типа универсального метода или конструктора также стираются, если сигнатура метода или конструктора удалена.
Удаление подписи универсального метода не имеет параметров типа.
В следующем сообщении об ошибке содержатся некоторые мысли Маурицио Симадамора, разработчика компилятора, и Алекса Бакли, одного из авторов JLS, о причинах такого поведения: https://bugs.openjdk.java.net/browse / JDK-6400189 . (Короче говоря, это упрощает спецификацию.)
Если это небезопасно, почему разрешено использовать необработанный тип?
Вот еще одна цитата из JLS 4.8:
Использование необработанных типов допускается только в качестве уступки совместимости устаревшего кода. Использование необработанных типов в коде, написанном после введения универсальности в язык программирования Java, настоятельно не рекомендуется. Вполне возможно, что будущие версии языка программирования Java будут запрещать использование необработанных типов.
Effective Java 2nd Edition также имеет следующее:
Учитывая, что вы не должны использовать необработанные типы, почему разработчики языка разрешили это? Для обеспечения совместимости.
Платформа Java собиралась вступить во второе десятилетие, когда были представлены дженерики, и существовало огромное количество Java-кода, который не использовал дженерики. Было сочтено критически важным, чтобы весь этот код оставался законным и мог взаимодействовать с новым кодом, который использует дженерики. Должно быть допустимо передавать экземпляры параметризованных типов в методы, которые были разработаны для использования с обычными типами, и наоборот. Это требование, известное как совместимость миграции , привело к принятию решения о поддержке необработанных типов.
Таким образом, необработанные типы никогда не должны использоваться в новом коде. Вы должны всегда использовать параметризованные типы .
Есть ли исключения?
К сожалению, из-за непатентованного универсального кода Java есть два исключения, где необработанные типы должны использоваться в новом коде:
Литералы класса, например List.class, неList<String>.class
instanceofоперанд, например o instanceof Set, неo instanceof Set<String>
Что вы имеете в виду, что "дженерики Java не являются reified"?
Карл Дж
7
Во втором исключении синтаксис o instanceof Set<?>также разрешен, чтобы избежать необработанного типа (хотя это только поверхностно в этом случае).
Пол Беллора
1
Необработанные типы очень полезны и сокращают шаблонный код в случае поиска JNDI для bean-компонента, расширяющего интерфейс. Это устраняет необходимость написания nудаленных компонентов для каждого реализующего класса с идентичным кодом.
djmj
8
«Нерасположенный» - это еще один способ сказать, что они стерты. Компилятор знает, что такое общие параметры, но эта информация не передается в сгенерированный байт-код. JLS требует, чтобы литералы класса не имели параметров типа.
Эрик Дж. Хагстрем
2
@ OldCurmudgeon Это интересно. Я имею в виду, что официально это ни то , ни другое , потому что литерал класса определен просто TypeName.class, где TypeNameпростой идентификатор ( jls ). Говоря гипотетически, я думаю, что на самом деле это тоже может быть. Может быть, в качестве подсказки, List<String>.classэто вариант, который JLS специально вызывает ошибку компилятора, поэтому, если они когда-нибудь добавят ее в язык, я ожидаю, что это тот, который они используют.
Radiodef
62
Что такое необработанные типы в Java, и почему я часто слышу, что они не должны использоваться в новом коде?
Raw-типы - это древняя история языка Java. В начале были Collectionsи не держали Objectsничего больше и не меньше. Каждая операция по желанию Collectionsприведена Objectк желаемому типу.
List aList =newArrayList();String s ="Hello World!";
aList.add(s);String c =(String)aList.get(0);
Хотя это работало большую часть времени, ошибки все же случались
List aNumberList =newArrayList();String one ="1";//Number one
aNumberList.add(one);Integer iOne =(Integer)aNumberList.get(0);//Insert ClassCastException here
Старые коллекции без типов не могли обеспечить безопасность типов, поэтому программист должен был помнить, что он хранит в коллекции.
Обобщения, которые были изобретены, чтобы обойти это ограничение, разработчик объявлял бы сохраненный тип один раз, и компилятор сделал бы это вместо этого.
List<String> aNumberList =newArrayList<String>();
aNumberList.add("one");Integer iOne = aNumberList.get(0);//Compile time errorString sOne = aNumberList.get(0);//works fine
Для сравнения:
// Old style collections now known as raw typesList aList =newArrayList();//Could contain anything// New style collections with GenericsList<String> aList =newArrayList<String>();//Contains only Strings
Более сложный сравниваемый интерфейс:
//raw, not type save can compare with Other classesclassMyCompareAbleimplementsCompareAble{int id;publicint compareTo(Object other){returnthis.id -((MyCompareAble)other).id;}}//GenericclassMyCompareAbleimplementsCompareAble<MyCompareAble>{int id;publicint compareTo(MyCompareAble other){returnthis.id - other.id;}}
Обратите внимание, что невозможно реализовать CompareAbleинтерфейс compareTo(MyCompareAble)с необработанными типами. Почему вы не должны использовать их:
Все, что Objectхранится в a Collection, должно быть разыграно перед использованием.
Использование обобщений позволяет проверять время компиляции
Использование необработанных типов аналогично сохранению каждого значения Object
Что делает компилятор: Generics обратно совместимы, они используют те же классы Java, что и необработанные типы. Магия происходит в основном во время компиляции.
List<String> someStrings =newArrayList<String>();
someStrings.add("one");String one = someStrings.get(0);
Будет скомпилировано как:
List someStrings =newArrayList();
someStrings.add("one");String one =(String)someStrings.get(0);
Это тот же код, который вы написали бы, если бы использовали непосредственные типы. Хотя я не уверен, что происходит с CompareAbleинтерфейсом, я предполагаю, что он создает две compareToфункции, одну из которых принимает a, MyCompareAbleа другую принимает Objectи передает его первой после приведения.
Чтобы создать параметризованный тип Box<T>, вы предоставляете фактический аргумент типа для параметра формального типа T:
Box<Integer> intBox =newBox<>();
Если фактический аргумент типа опущен, вы создаете необработанный тип Box<T>:
Box rawBox =newBox();
Следовательно, Boxэто необработанный тип универсального типа Box<T>. Однако неуниверсальный класс или тип интерфейса не является необработанным типом.
Необработанные типы отображаются в устаревшем коде, потому что многие классы API (такие как классы Collections) не были универсальными до JDK 5.0. При использовании необработанных типов вы, по сути, получаете пре-родовое поведение - a Boxдает вам Objects. Для обратной совместимости допускается присвоение параметризованного типа его необработанному типу:
Box<String> stringBox =newBox<>();Box rawBox = stringBox;// OK
Но если вы назначите необработанный тип параметризованному типу, вы получите предупреждение:
Box rawBox =newBox();// rawBox is a raw type of Box<T>Box<Integer> intBox = rawBox;// warning: unchecked conversion
Вы также получите предупреждение, если используете необработанный тип для вызова универсальных методов, определенных в соответствующем универсальном типе:
Предупреждение показывает, что необработанные типы обходят общие проверки типов, откладывая перехват небезопасного кода до времени выполнения. Поэтому вам следует избегать использования необработанных типов.
Раздел Erasure Type содержит больше информации о том, как компилятор Java использует необработанные типы.
Непроверенные сообщения об ошибках
Как упоминалось ранее, при смешивании устаревшего кода с универсальным кодом вы можете столкнуться с предупреждающими сообщениями, подобными следующим:
Примечание: Example.java использует непроверенные или небезопасные операции.
Примечание: Перекомпилируйте с -Xlint: не проверено для деталей.
Это может произойти при использовании старого API, который работает с необработанными типами, как показано в следующем примере:
publicclassWarningDemo{publicstaticvoid main(String[] args){Box<Integer> bi;
bi = createBox();}staticBox createBox(){returnnewBox();}}
Термин «непроверенный» означает, что у компилятора недостаточно информации о типе, чтобы выполнить все проверки типов, необходимые для обеспечения безопасности типов. По умолчанию предупреждение «unchecked» отключено, хотя компилятор дает подсказку. Чтобы увидеть все «непроверенные» предупреждения, перекомпилируйте с -Xlint: unchecked.
Перекомпиляция предыдущего примера с -Xlint: unchecked открывает следующую дополнительную информацию:
WarningDemo.java:4: warning:[unchecked] unchecked conversion
found :Box
required:Box<java.lang.Integer>
bi = createBox();^1 warning
Чтобы полностью отключить непроверенные предупреждения, используйте флаг -Xlint: -unchecked. @SuppressWarnings("unchecked")Аннотацию подавляет непроверенные предупреждения. Если вы не знакомы с @SuppressWarningsсинтаксисом, см. Аннотации.
«Необработанный» тип в Java - это класс, который не является универсальным и имеет дело с «необработанными» объектами, а не с типизированными параметрами универсального типа.
Например, до того как Java-дженерики стали доступны, вы должны использовать класс коллекции следующим образом:
LinkedList list =newLinkedList();
list.add(newMyObject());MyObject myObject =(MyObject)list.get(0);
Когда вы добавляете свой объект в список, его не волнует, какой это тип объекта, и когда вы получаете его из списка, вы должны явно привести его к ожидаемому типу.
Используя дженерики, вы удаляете «неизвестный» фактор, потому что вы должны явно указать, какой тип объектов может идти в списке:
LinkedList<MyObject> list =newLinkedList<MyObject>();
list.add(newMyObject());MyObject myObject = list.get(0);
Обратите внимание, что при использовании дженериков вам не нужно приводить объект, полученный из вызова get, коллекция предопределена для работы только с MyObject. Этот факт является основным движущим фактором для дженериков. Это превращает источник ошибок времени выполнения во что-то, что можно проверить во время компиляции.
В частности, необработанный тип - это то, что вы получаете, когда просто опускаете параметры типа для универсального типа. Необработанные типы в действительности были только функцией обратной совместимости и потенциально могут быть удалены. Вы можете получить похожее поведение, используя? параметры подстановочных знаков.
Джон Флатнесс
@zerocrates: похожие, но разные! Использование по- ?прежнему предлагает безопасность типов. Я покрыл это в своем ответе.
полигенасмазочные материалы
19
privatestaticList<String> list =newArrayList<String>();
Вы должны указать тип-параметра.
Предупреждение предупреждает, что типы, которые определены для поддержки обобщений, должны быть параметризованы, а не использовать их необработанную форму.
Listопределяется поддержки дженериков: public class List<E>. Это позволяет выполнять многие безопасные для типов операции, которые проверяются во время компиляции.
Теперь заменен на алмазный вывод в Java 7 -private static List<String> list = new ArrayList<>();
Ян Кэмпбелл
14
Что такое необработанный тип и почему я часто слышу, что его не следует использовать в новом коде?
«Необработанный тип» - это использование универсального класса без указания аргумента (ов) типа для его параметризованного типа (типов), например, с использованием Listвместо List<String>. Когда дженерики были введены в Java, несколько классов были обновлены для использования дженериков. Использование этих классов в качестве «необработанного типа» (без указания аргумента типа) позволило устаревшему коду все еще компилироваться.
«Необработанные типы» используются для обратной совместимости. Их использование в новом коде не рекомендуется, поскольку использование универсального класса с аргументом типа обеспечивает более строгую типизацию, что, в свою очередь, может улучшить понятность кода и привести к более раннему выявлению потенциальных проблем.
Какая альтернатива, если мы не можем использовать необработанные типы, и как это лучше?
Предпочтительной альтернативой является использование обобщенных классов по назначению - с подходящим аргументом типа (например List<String>). Это позволяет программисту более конкретно указывать типы, сообщает будущим разработчикам больше смысла о предполагаемом использовании переменной или структуры данных, а также позволяет компилятору обеспечивать лучшую безопасность типов. Вместе эти преимущества могут улучшить качество кода и предотвратить появление некоторых ошибок кодирования.
Например, для метода, в котором программист хочет убедиться, что переменная List с именем 'names' содержит только строки:
List<String> names =newArrayList<String>();
names.add("John");// OK
names.add(newInteger(1));// compile error
Ах, так соблазнительно скопировать polygenelubricantsссылки «необработанного типа» из stackoverflow.com/questions/2770111/… в мой собственный ответ, но я полагаю, что оставлю их для использования в своем собственном ответе.
Берт Ф.
1
да, я, по сути, копировал и вставлял этот сегмент везде, где люди используют необработанные типы в stackoverflow, и в конце концов решил просто иметь один вопрос, на который можно ссылаться с этого момента. Я надеюсь, что это хороший вклад для сообщества.
полигенасмазочные материалы
1
@polygenelubricants, которые я заметил - мы задали одни и те же вопросы :-)
Берт Ф
1
@ ha9u63ar: Действительно. В общем краткие и простые ответы, по крайней мере, так же хороши, как и длинные и общепринятые.
displayName
Что такое "сильнее сироп"?
carloswm85
12
Компилятор хочет, чтобы вы написали это:
privatestaticList<String> list =newArrayList<String>();
потому что в противном случае вы можете добавить любой тип, который вам нравится list, делая создание экземпляров new ArrayList<String>()бессмысленным. Обобщения Java являются только функцией времени компиляции, поэтому созданный объект с new ArrayList<String>()радостью примет элементы Integerили JFrameэлементы, если они назначены для ссылки на «необработанный тип» List- сам объект ничего не знает о том, какие типы он должен содержать, только компилятор.
ArrayList<String> arrэто ArrayListссылочная переменная с типом, Stringкоторая ссылается на ArralyListобъект типа String. Это означает, что он может содержать только объект типа String.
Это строгий, а Stringне необработанный тип, поэтому он никогда не выдаст предупреждение.
arr.add("hello");// alone statement will compile successfully and no warning.
arr.add(23);//prone to compile time error.//error: no suitable method found for add(int)
Дело 2
В этом случае ArrayList<String> arrэто строгий тип, но ваш объект new ArrayList();является необработанным типом.
arr.add("hello");//alone this compile but raise the warning.
arr.add(23);//again prone to compile time error.//error: no suitable method found for add(int)
здесь arrстрогий тип. Таким образом, это приведет к ошибке времени компиляции при добавлении integer.
Предупреждение : - RawОбъект типа связан с Strictтипом ссылочной переменной ArrayList.
Дело 3
В этом случае ArrayList arrэто необработанный тип, но ваш объект new ArrayList<String>();является строгим типом.
arr.add("hello");
arr.add(23);//compiles fine but raise the warning.
Он добавит в него любой тип объекта, потому что arrэто необработанный тип.
Предупреждение : - StrictОбъект rawтипа ссылается на переменную, на которую ссылается тип.
Сырья типа является отсутствие в параметре типа при использовании универсального типа.
Сырье типа не следует использовать , поскольку это может привести к ошибкам во время выполнения, как и вставки doubleв то , что должно было быть Setв intс.
Set set =newHashSet();
set.add(3.45);//ok
При извлечении материала из Set, вы не знаете, что выходит. Давайте предположим, что вы ожидаете, что это все ints, к которому вы приводите Integer; исключение во время выполнения, когда doubleприходит 3.45.
Если к вашему параметру добавлен параметр типаSet , вы сразу получите ошибку компиляции. Эта упреждающая ошибка позволяет устранить проблему до того, как что-то взорвется во время выполнения (что сэкономит время и усилия).
Set<Integer> set =newHashSet<Integer>();
set.add(3.45);//NOT ok.
Как уже упоминалось в принятом ответе, вы теряете всю поддержку обобщений в коде необработанного типа. Каждый параметр типа преобразуется в его стирание (что в приведенном выше примере просто Object).
Что сказать, что ваш listесть Listиз unespecified объектов. То есть Java не знает, какие объекты находятся внутри списка. Затем, когда вы хотите перебрать список, вы должны привести каждый элемент, чтобы иметь доступ к свойствам этого элемента (в данном случае, String).
В целом, лучше параметризовать коллекции, так что у вас не будет проблем с преобразованием, вы сможете добавлять только элементы параметризованного типа, и ваш редактор предложит вам подходящие методы для выбора.
privatestaticList<String> list =newArrayList<String>();
Необработанные типы относятся к использованию универсального типа без указания параметра типа.
Например ,
Список является необработанным типом, а List<String>является параметризованным типом.
Когда дженерики были представлены в JDK 1.5, необработанные типы были сохранены только для обеспечения обратной совместимости со старыми версиями Java. Хотя использование необработанных типов все еще возможно,
Их следует избегать :
Они обычно требуют приведения
Они не являются безопасными по типу, и некоторые важные виды ошибок будут появляться только во время выполнения
Они менее выразительны и не документируют себя так же, как параметризованные типы.
Пример
import java.util.*;publicfinalclassAvoidRawTypes{void withRawType(){//Raw List doesn't self-document, //doesn't state explicitly what it can containList stars =Arrays.asList("Arcturus","Vega","Altair");Iterator iter = stars.iterator();while(iter.hasNext()){String star =(String) iter.next();//cast needed
log(star);}}void withParameterizedType(){List<String> stars =Arrays.asList("Spica","Regulus","Antares");for(String star: stars){
log(star);}}privatevoid log(Object message){System.out.println(Objects.toString(message));}}
Я нашел эту страницу после того, как выполнил несколько типовых упражнений и получил точно такую же загадку.
============== Я пошел из этого кода, как показано в примере ===============
publicstaticvoid main(String[] args)throwsIOException{Map wordMap =newHashMap();if(args.length >0){for(int i =0; i < args.length; i++){
countWord(wordMap, args[i]);}}else{
getWordFrequency(System.in, wordMap);}for(Iterator i = wordMap.entrySet().iterator(); i.hasNext();){Map.Entry entry =(Map.Entry) i.next();System.out.println(entry.getKey()+" :\t"+ entry.getValue());}
====================== К этому коду ========================
publicstaticvoid main(String[] args)throwsIOException{// replace with TreeMap to get them sorted by nameMap<String,Integer> wordMap =newHashMap<String,Integer>();if(args.length >0){for(int i =0; i < args.length; i++){
countWord(wordMap, args[i]);}}else{
getWordFrequency(System.in, wordMap);}for(Iterator<Entry<String,Integer>> i = wordMap.entrySet().iterator(); i.hasNext();){Entry<String,Integer> entry = i.next();System.out.println(entry.getKey()+" :\t"+ entry.getValue());}}
Ответы:
Что такое сырой тип?
Спецификация языка Java определяет необработанный тип следующим образом:
JLS 4.8 Необработанные типы
Вот пример для иллюстрации:
Здесь
MyType<E>
- параметризованный тип ( JLS 4.5 ). Обычно в разговорной речи называют этот тип простоMyType
для краткости, но формально это имяMyType<E>
.mt
имеет необработанный тип (и генерирует предупреждение о компиляции) по первому пункту в приведенном выше определении;inn
также имеет необработанный тип по третьему пункту.MyType.Nested
не параметризованный тип, хотя это тип члена параметризованного типаMyType<E>
, потому что этоstatic
.mt1
иmt2
оба объявлены с фактическими параметрами типа, поэтому они не являются необработанными типами.Что такого особенного в необработанных типах?
По сути, необработанные типы ведут себя так же, как и до появления дженериков. То есть, следующее является полностью законным во время компиляции.
Приведенный выше код работает просто отлично, но предположим, что у вас также есть следующее:
Теперь мы сталкиваемся с проблемами во время выполнения, потому что
names
содержит что-то, что не являетсяinstanceof String
.Предположительно, если вы хотите
names
содержать толькоString
, возможно , вы все еще могли бы использовать необработанный тип и вручную проверять каждыйadd
сам, а затем вручную приводить кString
каждому элементу изnames
. Еще лучше , хотя НЕ использовать необработанный тип и позволить компилятору сделать всю работу за вас , используя всю мощь Java-дженериков.Конечно, если вы НЕ хотите ,
names
чтобы позволитьBoolean
, то вы можете объявить его какList<Object> names
и приведенный выше код будет компилироваться.Смотрите также
Чем необработанный тип отличается от использования в
<Object>
качестве параметров типа?Ниже приводится цитата из Effective Java 2nd Edition, пункт 23. Не используйте необработанные типы в новом коде :
Чтобы проиллюстрировать это, рассмотрим следующий метод, который принимает
List<Object>
и добавляет anew Object()
.Обобщения в Java инвариантны. A
List<String>
не является aList<Object>
, поэтому следующее генерирует предупреждение компилятора:Если бы вы объявили,
appendNewObject
что вList
качестве параметра принимается необработанный тип , он скомпилируется, и поэтому вы потеряете безопасность типов, которую вы получаете от обобщений.Смотрите также
<E extends Number>
и<Number>
?Чем необработанный тип отличается от использования
<?>
в качестве параметра типа?List<Object>
иList<String>
т. д. всеList<?>
, так что может быть заманчиво просто сказать, что они простоList
вместо. Тем не менее, есть существенное отличие: поскольку aList<E>
определяет толькоadd(E)
, вы не можете добавить любой произвольный объект в aList<?>
. С другой стороны, поскольку необработанный типList
не имеет безопасности типов, вы можете получитьadd
что угодноList
.Рассмотрим следующий вариант предыдущего фрагмента:
Компилятор прекрасно защитил вас от возможного нарушения неизменности типов
List<?>
! Если бы вы объявили параметр как необработанный типList list
, то код скомпилировался бы, и вы нарушили бы инвариант типаList<String> names
.Необработанный тип - это стирание этого типа.
Вернуться к JLS 4.8:
Проще говоря, когда используются сырой типа, конструкторы, методы экземпляра и не-
static
полей также удаляется .Возьмите следующий пример:
Когда мы используем сырье
MyType
, оно такжеgetNames
стирается, так что оно возвращает сырьеList
!JLS 4.6 продолжает объяснять следующее:
В следующем сообщении об ошибке содержатся некоторые мысли Маурицио Симадамора, разработчика компилятора, и Алекса Бакли, одного из авторов JLS, о причинах такого поведения: https://bugs.openjdk.java.net/browse / JDK-6400189 . (Короче говоря, это упрощает спецификацию.)
Если это небезопасно, почему разрешено использовать необработанный тип?
Вот еще одна цитата из JLS 4.8:
Effective Java 2nd Edition также имеет следующее:
Таким образом, необработанные типы никогда не должны использоваться в новом коде. Вы должны всегда использовать параметризованные типы .
Есть ли исключения?
К сожалению, из-за непатентованного универсального кода Java есть два исключения, где необработанные типы должны использоваться в новом коде:
List.class
, неList<String>.class
instanceof
операнд, напримерo instanceof Set
, неo instanceof Set<String>
Смотрите также
Collection<String>.class
незаконно?источник
o instanceof Set<?>
также разрешен, чтобы избежать необработанного типа (хотя это только поверхностно в этом случае).n
удаленных компонентов для каждого реализующего класса с идентичным кодом.TypeName.class
, гдеTypeName
простой идентификатор ( jls ). Говоря гипотетически, я думаю, что на самом деле это тоже может быть. Может быть, в качестве подсказки,List<String>.class
это вариант, который JLS специально вызывает ошибку компилятора, поэтому, если они когда-нибудь добавят ее в язык, я ожидаю, что это тот, который они используют.Raw-типы - это древняя история языка Java. В начале были
Collections
и не держалиObjects
ничего больше и не меньше. Каждая операция по желаниюCollections
приведенаObject
к желаемому типу.Хотя это работало большую часть времени, ошибки все же случались
Старые коллекции без типов не могли обеспечить безопасность типов, поэтому программист должен был помнить, что он хранит в коллекции.
Обобщения, которые были изобретены, чтобы обойти это ограничение, разработчик объявлял бы сохраненный тип один раз, и компилятор сделал бы это вместо этого.
Для сравнения:
Более сложный сравниваемый интерфейс:
Обратите внимание, что невозможно реализовать
CompareAble
интерфейсcompareTo(MyCompareAble)
с необработанными типами. Почему вы не должны использовать их:Object
хранится в aCollection
, должно быть разыграно перед использованием.Object
Что делает компилятор: Generics обратно совместимы, они используют те же классы Java, что и необработанные типы. Магия происходит в основном во время компиляции.
Будет скомпилировано как:
Это тот же код, который вы написали бы, если бы использовали непосредственные типы. Хотя я не уверен, что происходит с
CompareAble
интерфейсом, я предполагаю, что он создает двеcompareTo
функции, одну из которых принимает a,MyCompareAble
а другую принимаетObject
и передает его первой после приведения.Какие альтернативы необработанным типам: Используйте дженерики
источник
Необработанный тип - это имя универсального класса или интерфейса без аргументов типа. Например, учитывая общий класс Box:
Чтобы создать параметризованный тип
Box<T>
, вы предоставляете фактический аргумент типа для параметра формального типаT
:Если фактический аргумент типа опущен, вы создаете необработанный тип
Box<T>
:Следовательно,
Box
это необработанный тип универсального типаBox<T>
. Однако неуниверсальный класс или тип интерфейса не является необработанным типом.Необработанные типы отображаются в устаревшем коде, потому что многие классы API (такие как классы Collections) не были универсальными до JDK 5.0. При использовании необработанных типов вы, по сути, получаете пре-родовое поведение - a
Box
дает вамObject
s. Для обратной совместимости допускается присвоение параметризованного типа его необработанному типу:Но если вы назначите необработанный тип параметризованному типу, вы получите предупреждение:
Вы также получите предупреждение, если используете необработанный тип для вызова универсальных методов, определенных в соответствующем универсальном типе:
Предупреждение показывает, что необработанные типы обходят общие проверки типов, откладывая перехват небезопасного кода до времени выполнения. Поэтому вам следует избегать использования необработанных типов.
Раздел Erasure Type содержит больше информации о том, как компилятор Java использует необработанные типы.
Непроверенные сообщения об ошибках
Как упоминалось ранее, при смешивании устаревшего кода с универсальным кодом вы можете столкнуться с предупреждающими сообщениями, подобными следующим:
Это может произойти при использовании старого API, который работает с необработанными типами, как показано в следующем примере:
Термин «непроверенный» означает, что у компилятора недостаточно информации о типе, чтобы выполнить все проверки типов, необходимые для обеспечения безопасности типов. По умолчанию предупреждение «unchecked» отключено, хотя компилятор дает подсказку. Чтобы увидеть все «непроверенные» предупреждения, перекомпилируйте с -Xlint: unchecked.
Перекомпиляция предыдущего примера с -Xlint: unchecked открывает следующую дополнительную информацию:
Чтобы полностью отключить непроверенные предупреждения, используйте флаг -Xlint: -unchecked.
@SuppressWarnings("unchecked")
Аннотацию подавляет непроверенные предупреждения. Если вы не знакомы с@SuppressWarnings
синтаксисом, см. Аннотации.Первоначальный источник: Java Tutorials
источник
«Необработанный» тип в Java - это класс, который не является универсальным и имеет дело с «необработанными» объектами, а не с типизированными параметрами универсального типа.
Например, до того как Java-дженерики стали доступны, вы должны использовать класс коллекции следующим образом:
Когда вы добавляете свой объект в список, его не волнует, какой это тип объекта, и когда вы получаете его из списка, вы должны явно привести его к ожидаемому типу.
Используя дженерики, вы удаляете «неизвестный» фактор, потому что вы должны явно указать, какой тип объектов может идти в списке:
Обратите внимание, что при использовании дженериков вам не нужно приводить объект, полученный из вызова get, коллекция предопределена для работы только с MyObject. Этот факт является основным движущим фактором для дженериков. Это превращает источник ошибок времени выполнения во что-то, что можно проверить во время компиляции.
источник
?
прежнему предлагает безопасность типов. Я покрыл это в своем ответе.Вы должны указать тип-параметра.
Предупреждение предупреждает, что типы, которые определены для поддержки обобщений, должны быть параметризованы, а не использовать их необработанную форму.
List
определяется поддержки дженериков:public class List<E>
. Это позволяет выполнять многие безопасные для типов операции, которые проверяются во время компиляции.источник
private static List<String> list = new ArrayList<>();
Что такое необработанный тип и почему я часто слышу, что его не следует использовать в новом коде?
«Необработанный тип» - это использование универсального класса без указания аргумента (ов) типа для его параметризованного типа (типов), например, с использованием
List
вместоList<String>
. Когда дженерики были введены в Java, несколько классов были обновлены для использования дженериков. Использование этих классов в качестве «необработанного типа» (без указания аргумента типа) позволило устаревшему коду все еще компилироваться.«Необработанные типы» используются для обратной совместимости. Их использование в новом коде не рекомендуется, поскольку использование универсального класса с аргументом типа обеспечивает более строгую типизацию, что, в свою очередь, может улучшить понятность кода и привести к более раннему выявлению потенциальных проблем.
Какая альтернатива, если мы не можем использовать необработанные типы, и как это лучше?
Предпочтительной альтернативой является использование обобщенных классов по назначению - с подходящим аргументом типа (например
List<String>
). Это позволяет программисту более конкретно указывать типы, сообщает будущим разработчикам больше смысла о предполагаемом использовании переменной или структуры данных, а также позволяет компилятору обеспечивать лучшую безопасность типов. Вместе эти преимущества могут улучшить качество кода и предотвратить появление некоторых ошибок кодирования.Например, для метода, в котором программист хочет убедиться, что переменная List с именем 'names' содержит только строки:
источник
polygenelubricants
ссылки «необработанного типа» из stackoverflow.com/questions/2770111/… в мой собственный ответ, но я полагаю, что оставлю их для использования в своем собственном ответе.Компилятор хочет, чтобы вы написали это:
потому что в противном случае вы можете добавить любой тип, который вам нравится
list
, делая создание экземпляровnew ArrayList<String>()
бессмысленным. Обобщения Java являются только функцией времени компиляции, поэтому созданный объект сnew ArrayList<String>()
радостью примет элементыInteger
илиJFrame
элементы, если они назначены для ссылки на «необработанный тип»List
- сам объект ничего не знает о том, какие типы он должен содержать, только компилятор.источник
Здесь я рассматриваю несколько случаев, с помощью которых вы можете прояснить концепцию
Дело 1
ArrayList<String> arr
этоArrayList
ссылочная переменная с типом,String
которая ссылается наArralyList
объект типаString
. Это означает, что он может содержать только объект типа String.Это строгий, а
String
не необработанный тип, поэтому он никогда не выдаст предупреждение.Дело 2
В этом случае
ArrayList<String> arr
это строгий тип, но ваш объектnew ArrayList();
является необработанным типом.здесь
arr
строгий тип. Таким образом, это приведет к ошибке времени компиляции при добавленииinteger
.Дело 3
В этом случае
ArrayList arr
это необработанный тип, но ваш объектnew ArrayList<String>();
является строгим типом.Он добавит в него любой тип объекта, потому что
arr
это необработанный тип.источник
Сырья типа является отсутствие в параметре типа при использовании универсального типа.
Сырье типа не следует использовать , поскольку это может привести к ошибкам во время выполнения, как и вставки
double
в то , что должно было бытьSet
вint
с.При извлечении материала из
Set
, вы не знаете, что выходит. Давайте предположим, что вы ожидаете, что это всеint
s, к которому вы приводитеInteger
; исключение во время выполнения, когдаdouble
приходит 3.45.Если к вашему параметру добавлен параметр типа
Set
, вы сразу получите ошибку компиляции. Эта упреждающая ошибка позволяет устранить проблему до того, как что-то взорвется во время выполнения (что сэкономит время и усилия).источник
Вот еще один случай, когда необработанные типы будут кусать вас:
Как уже упоминалось в принятом ответе, вы теряете всю поддержку обобщений в коде необработанного типа. Каждый параметр типа преобразуется в его стирание (что в приведенном выше примере просто
Object
).источник
Что сказать, что ваш
list
естьList
из unespecified объектов. То есть Java не знает, какие объекты находятся внутри списка. Затем, когда вы хотите перебрать список, вы должны привести каждый элемент, чтобы иметь доступ к свойствам этого элемента (в данном случае, String).В целом, лучше параметризовать коллекции, так что у вас не будет проблем с преобразованием, вы сможете добавлять только элементы параметризованного типа, и ваш редактор предложит вам подходящие методы для выбора.
источник
учебная страница .
Необработанный тип - это имя универсального класса или интерфейса без аргументов типа. Например, учитывая общий класс Box:
Чтобы создать параметризованный тип Box, вы предоставляете фактический аргумент типа для параметра формального типа T:
Если фактический аргумент типа опущен, вы создаете необработанный тип Box:
источник
Избегайте необработанных типов
Например ,
Список является необработанным типом, а
List<String>
является параметризованным типом.Когда дженерики были представлены в JDK 1.5, необработанные типы были сохранены только для обеспечения обратной совместимости со старыми версиями Java. Хотя использование необработанных типов все еще возможно,
Их следует избегать :
Они менее выразительны и не документируют себя так же, как параметризованные типы. Пример
Для справки : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
источник
Я нашел эту страницу после того, как выполнил несколько типовых упражнений и получил точно такую же загадку.
============== Я пошел из этого кода, как показано в примере ===============
====================== К этому коду ========================
================================================== =============================
Это может быть безопаснее, но понадобилось 4 часа, чтобы разобраться в философии ...
источник
Сырые типы хороши, когда они выражают то, что вы хотите выразить.
Например, функция десериализации может возвращать a
List
, но она не знает тип элемента списка. ТакList
что соответствующий тип возврата здесь.источник