Дженерики
Ограничьи элементы в коллекции до определенного типа.
термин
Несколько заметок:
Параметризованные типы и примитивные типы совместимы друг с другом
ArrayList Collection1 = новый ArrayList <Integer> (); // Pass, без WarningArraylist <Integer> collection2 = new ArrayList (); // Pass, есть предупреждение
Параметризованные типы не учитывают отношения наследования параметров типа
ArrayList <string> collection3 = new ArrayList <Object> (); // Компиляция не проходит ArrayList <Object> collection4 = new ArrayList <string> (); // Компиляция не проходит
но
ArrayList Collection5 = new ArrayList <Integer> (); ArrayList <string> collection6 = collection5; // Составлено
"?" Подстановочный знак
"?" означает любой тип. Используйте "?" Символ подстановочного знака для обозначения различных параметризованных типов. Он может вызвать методы, которые не связаны с методом параметризации (например, size () и не могут вызовать методы, связанные с параметризацией (например, метод add ())
Расширение подстановочного знака
Квалифицировать верхнюю границу символов подстановочных знаков
ArrayList <? Extends Number> Collection1 = New ArrayList <Integer> (); // Компилирование ArrayList <? extends №> collection2 = new ArrayList <string> (); // компилируется не
Квалифицировать нижнюю границу символов подстановочных знаков
ArrayList <? Super Integer> Collection3 = New ArrayList <Cumber> (); // Скомпилируется ArrayList <? Super Integer> Collection4 = New ArrayList <string> (); // Компилирование не
Пользовательские общие методы
C ++ Функции шаблона
Шаблон <класс t> t добавить (t x, t y) {return (t) (x+y);}Дженерики Java в основном реализованы полностью в компиляторе, используемой компилятором для выполнения чеков типов и суждений типа, а затем генерировать обычный негенерический байт-код. Эта методика реализации - «стирание».
«Стереть» экземпляр
Дженерики предоставляются компилятору Javac для определения типа ввода коллекции. Когда компилятор собирает коллекцию с описанием типа, информация «Тип» будет удалена.
открытый класс generalest {public static void main (string [] args) {new generalSt (). testType (); } public void testtype () {arraylist <Integer> collection1 = new ArrayList <Integer> (); Arraylist <string> collection2 = new ArrayList <string> (); System.out.println (collection1.getClass () == collection2.getClass ()); // Типы классов из этих двух одинаково, то есть Bytecode является той же системой. // класс java.util.arraylist, и нет фактической информации о параметре типа}}Выход
истинный
java.util.arraylist
Используйте отражение, чтобы пропустить компилятор и добавить другие типы данных в общий сбор.
Только ссылочные типы могут использоваться в качестве фактических параметров для общих методов:
открытый класс generalest {public static void main (string [] args) {swap (new String [] {"111", "222"}, 0,1); // компилирован по // swap (new int [] {1,2}, 0,1); // Скомпилируйте, не компилируя, потому что int не является ссылочным типом подсасывания (новое целое число [] {1,2}, 0,1); // компилирование по}/*обменивать элементы i-th и jth массива a*/public static <t> void swap (t [] a, int i, int j) {t temp = a [i]; a [i] = a [j]; a [j] = temp; }}Но обратите внимание, что базовые типы иногда могут использоваться в качестве фактических параметров, потому что есть автоматическая упаковка и распаковка. Пример (скомпилирован и прошел):
открытый класс generalest {public static void main (string [] args) {new generalSt (). testType (); int a = biggerone (3,5); // int и удвоить, получить обмен как номер номера B = Biggerone (3,5,5); // string и int Получить обмен как объект объекта c = biggerone ("1", 2); } // return y из x, y public static <t> t biggerone (t x, t y) {return y; }}В то же время этот пример также показывает, что, когда фактические параметры противоречивы, t берет пересечение, то есть первый общий родительский класс. Кроме того, если вы используете номер B = Biggerone (3,5,5); к строке C = Biggerone (3,5,5); Затем сообщается об ошибке компиляции:
Ошибка: (17, 29) Java: Несовместимые типы: предполагаемые типы не соответствуют верхнему пределу. Вывод: java.lang.number & java.lang.comparable <? Расширение java.lang.number & java.lang.comparable <? >>
Верхний предел: java.lang.string, java.lang.object
Но есть одна вещь, которую я не понял. Я пошаговая отладка в Idea и обнаружил, что результат выглядит следующим образом: общая отладка экрана-1 Я не знаю, почему B имеет тип двойного (но он будет компилировать и сообщать об ошибке при получении возврата на Double B). Я не знаю, имеет ли это какое -либо отношение к IDE. Отображает ли IDE наиболее точный тип этого объекта при отладке?
Тип вывод параметров типа
Процесс, с помощью которого компилятор судит фактические параметры типа общего метода, называется вывод типа.
Когда переменная определенного типа применяется только один из всех параметров и возвращаемых значений во всем списке параметров, она определяется на основе фактического типа приложения в то время при вызове метода. То есть тип общих параметров напрямую определяется на основе типа параметра или возвращаемого значения, проходящего при вызове метода. Например:
Swap (новая строка [3], 1,2) -> Статический <e> void swap (e [] a, int i, int j)
Когда переменная типа применяется во всех местах во всех параметрах и возвращаемых значениях всего списка параметров, если многие фактические типы приложений соответствуют одному типу при вызове метода, тип универсального параметра - это тип. Например:
Добавить (3,5) -> Статический <t> t добавить (t a, t b)
Когда переменная определенного типа применяется во многих местах во всех параметрах и возвращаемых значениях всего списка параметров, если фактические типы применения в многих местах соответствуют различным типам при вызове метода и нет возвращаемого значения, максимальный тип пересечения среди нескольких параметров, то есть первого общего родительского класса. Например:
заполнить (новое целое число [3], 3.5) -> Статическое <T> void fill (t a [], t v)
Фактическим соответствующим типом этого примера является число проблем, скомпилированных и запуска.
Когда переменная типа применяется во всех местах во всех параметрах и возвращаемых значениях всего списка параметров, если фактические типы приложений в многих местах соответствуют различным типам при вызове метода, и существует возвратное значение, тип возвращаемого значения дается приоритет, например: например:
int x = add (3,3,5) -> static <t> t add (t a, t b)
Приведенный выше пример скомпилированной ошибкой, и тип x изменяется на Float, также сообщается о ошибке, а изменение на число является успешным.
Примеры типового вывода типов параметров транзитивно:
Copy (New Integer [5], New String [5]) -> Static <t> void copy (t [] a, t [] b)
Этот пример делает, что фактический тип параметра является объектом и составлен через.
Копировать (новый ArrayList <string>, New Integer [5]) -> Static <t> void copy (collection <t> a, t [] b)
Этот пример непосредственно определяет переменную типа как тип строки на основе параметризованного экземпляра класса ArrayList, и сообщает об ошибке в компиляции.
Пользовательские общие классы
пример
открытый класс geneicDao <t> {public void add (t x) {} public t findbyid (int id) {return null; } public void delete (t obj) {} public void delete (int id) {} public void update (t obj) {} public t findbyUsername (string name) {return null; } public <t> set <t> findbyConditions (string where) {return null; }}Примечание. Когда переменная объявляется как общая, ее можно назвать только переменными экземпляра и методами (и встроенных типами), но не статическими переменными и статическими методами. Поскольку статические члены совместно используются параметризованными классами, статические члены не должны иметь параметров типа класса.
Сравнение общих методов и общих классов
пример:
открытый класс a <t> () {// метод члена общего класса, T ограничен T после публичного t memberfunc () {return null; } // Общий метод, здесь t и t отличаются от T o public static <t> t genericfunc (t a) {return null; } public static void main (string [] args) {// Скомпилируется без прохождения // целое число i = a <string> (). findbyusername ("s"); // Скомпилируется с помощью set <integer> set = a <string> (). FindByConditions ("s"); }}Здесь целое число i = a <string> (). Findbyusername ("s"); Скомпилируется и сообщит об ошибке:
Ошибка: (35, 61) Java: несовместимый тип: java.lang.string не может быть преобразован в java.lang.integer
Из этого примера можно видеть, что T общего метода и T класса A разные.
Дженерики и размышления
Получить фактические параметры типа общего посредством отражения
Используйте общие переменные в качестве параметров метода и используйте метод GetGenericParameterTypes класса метода, чтобы получить пример фактического типа параметра Generic:
открытый класс generalest {public static void main (string [] args) бросает исключение {getParamType (); } /*Используйте отражение для получения фактического типа параметра параметров метода* / public static void getParamType () выбросы Nosuchmethodexception {method method = generictest.class.getmethod ("ApplyMap", map.class); // Получить тип общих параметров типа метода [] types = method.getGenericParameterTypes (); System.out.println (типы [0]); // Параметризованный тип параметризованный тип ptype = (parameterizedtype) типы [0]; // primitive type System.out.println (ptype.getRawType ()); // Фактический тип параметров System.out.println (ptype.getActualtyPearguments () [0]); System.out.println (ptype.getActualtyPearguments () [1]); } /* Метод для тестирования типов параметров* / public static void ApplyMap (map <integer, string> map) {}}Результат вывода:
java.util.map <java.lang.integer, java.lang.string> Интерфейс java.util.mapclass java.lang.integerclass java.lang.string