Java Generics — что на самом деле в неограниченном подстановочном знаке?

#java #generics

#java #дженерики

Вопрос:

Если у меня есть следующий код :

 public static void main(String [] args) {  
        List <Integer> l2 = new ArrayList <Integer>();  
        List <?> l3 = l2;  
        test(l2);  
        test(l3);  
}  


public static void test(List <?> l) {  
        if (l instanceof List<?>)  
            System.out.println("true");  
}  
  

Это выведет:

 true  
true  
  

Из того, что я понимаю, <?> это reifiable type , что означает, что он имеет некоторый тип захвата (каким бы ни был этот тип), который доступен во время выполнения.

Вопросы:
a. В методе тестирования известно ли, что l2 имеет целочисленный тип (поскольку он был удален до вызова метода)? Как это перевести так, что Л (со 2) является экземпляром списка <?>?
б. Что о L3? Как это переводится?

Комментарии:

1. java не имеет проверяемых типов, поэтому метод тестирования ничего не знает, а instanceof никогда ничего не узнает об универсальных типах.

2. @jtahlborn: (и избиратель) JLS не согласен с вами .

3. к, больше думал о том, как это применимо в общем смысле к дженерикам. теперь я вижу, что это также относится к стандартным типам (которые можно использовать повторно). однако остальная часть моего утверждения остается в силе.

Ответ №1:

Я не верю <?> , что это подтверждено. Это просто единственный способ ссылаться на обобщенный тип без использования необработанной формы ( List ) . В обоих случаях вы просто выполняете ту же операцию, что и:

 if (l instanceof List) 
   ...
  

Редактировать

Действительно, я только что проверил, что они генерируют абсолютно идентичный байт-код, используете ли вы List<?> или List в instanceof .

Комментарии:

1. Но <?> это reifiable типа. Это единственный повторяемый тип для подстановочного знака .. вы можете проверить множество книг SCJP. Вот одна из ссылок angelikalanger.com/GenericsFAQ/FAQSections /…

2. @yap: В этой статье говорится, что <?> это можно проверить в том смысле, что после удаления не было потеряно никакой информации о типе списка (потому что для начала ничего не известно о параметре типа!).). Но это невозможно проверить в том смысле, что эта информация фактически доступна для объекта во время выполнения — во время выполнения вы не знаете , что это было a List<?> , а не a List или a List<Integer> .

3. Ответ, предоставленный Райаном Стюартом, более точен, чем ответ, предложенный Марком Питерсом. Пожалуйста, поправьте меня, если я ошибаюсь 🙂

Ответ №2:

Неограниченный подстановочный знак можно использовать только в том смысле, что информация о типе не теряется во время выполнения, потому что нет информации о типе, которую можно потерять. Что касается ваших вопросов:

a. Метод тестирования не знает, что l2 имеет целочисленный тип. Для метода тестирования это список, содержащий «что-то», и это все.

б. Нет «перевода». Это просто список неограниченного типа, передаваемый в качестве параметра методу, который принимает список неограниченного типа.