Список против Списка<Объект>
Почему мы теряем безопасность типов при использовании List
а не при использовании List<Object>
? Разве они не одно и то же?
РЕДАКТИРОВАТЬ: я обнаружил, что следующее дает ошибку компиляции
public class TestClass
{
static void func(List<Object> o, Object s){
o.add(s);
}
public static void main(String[] args){
func(new ArrayList<String>(), new Integer(1));
}
}
тогда как это не
public class TestClass
{
static void func(List o, Object s){
o.add(s);
}
public static void main(String[] args){
func(new ArrayList<String>(), new Integer(1));
}
}
Зачем?
5 ответов
Почему мы теряем безопасность типов при использовании
List
а не при использованииList<Object>
? Разве они не одно и то же?
Нет, они не одно и то же.
Если вы предоставляете API,
class API {
static List<Object> getList() { ... }
static void modifyList(List<Object> l) { ... }
}
и клиент использует это неправильно
List<Integer> list = API.getList();
API.modifyList(list);
for (Integer i : list) { ... } // Invalid
тогда, когда ваш API указывает List<Object>
они получают ошибку во время компиляции, но не когда API.getList()
возвращает List
а также API.modifyList(list)
занимает List
без параметров универсального типа.
РЕДАКТИРОВАТЬ:
В комментариях вы упомянули изменение
void func(List<Object> s, Object c) { s.add(c); }
в
void func(List s, Object c) { s.add(c); }
чтобы
func(new List<String>(), "");
должно сработать.
Это нарушает безопасность типов. Типобезопасный способ сделать это
<T> void func(List<? super T> s, T c) { s.add(c); }
который в основном говорит, что func
является параметризованной функцией, которая принимает List
тип которого может быть любым суперклассом T и значением типа T, и добавляет значение в список.
List
список некоторых типов, которые вы не знаете Это может быть List<String>
, List<Integer>
, так далее.
Это фактически эквивалентно List<?>
, или же List<? extends Object>
за исключением того, что он не документирует этот факт. Поддерживается только для обратной совместимости.
List<Object>
список объектовЛюбой объект любого типа может быть помещен в него, вопреки List<String>
Например, который принимает только строки.
Так что нет, это не одно и то же.
List<Object>
на самом деле не более безопасным, чем List
, Тем не менее Object
в коде подразумевается намерение. Когда кто-то еще смотрит на это позже, он может видеть, что вы целенаправленно выбрали Object
как тип, а не удивляться, если вы просто забыли поместить тип или сохраняете что-то еще и переносите его в другое место.
Поскольку код читается больше, чем пишется, подсказки о намерениях кода могут быть очень ценными в дальнейшем.
Причина, по которой вы получаете предупреждение компилятора при использовании List
вместо List<Object>
это когда у вас есть List
компилятор не знает, что это за List, поэтому пока вы можете рассматривать его как List<Object>
компилятор не может гарантировать, что в какой-то другой точке кода он не был установлен для ссылки на List<String>
и безопасность типа Generics не может быть проверена. Это на самом деле предупреждение компилятора: он говорит, что не может обеспечить безопасность типов обобщенных типов и не произойдет во время выполнения (пока в какой-то более поздний момент в коде не произойдет реальное приведение).
Для целей здесь вы можете сказать, что это одно и то же. Но, вероятно, вы почти никогда не заполняете List
с чистым экземпляром Object
, Они String
с или что-то. В этом примере List<Object>
технически использует дженерики, но не пользуется ими. Таким образом, он теряет проверку типов во время компиляции обобщений.
Тип Erasure - это один из ответов и обратная совместимость с до Java 1.5 и более строгой проверкой типов в случае первого.
Обобщения были введены в язык Java для обеспечения более строгой проверки типов во время компиляции и для поддержки универсального программирования. Для реализации универсальных шаблонов компилятор Java применяет стирание типов к:
Замените все параметры типа в универсальных типах их границами или Object, если параметры типа не ограничены. Таким образом, полученный байт-код содержит только обычные классы, интерфейсы и методы. При необходимости вставьте типовые отливки для сохранения типовой безопасности. Сгенерируйте мостовые методы для сохранения полиморфизма в расширенных универсальных типах. Стирание типа гарантирует, что для параметризованных типов не будут созданы новые классы; следовательно, универсальные шаблоны не несут дополнительных затрат времени выполнения.