1. Что именно является общим?
Перед обсуждением вывода типа мы должны просмотреть, что является общим. Дженерики являются новыми функциями Java SE 1.5. Суть Generics - это параметризованный тип, то есть тип данных, работающий в качестве параметра. С точки зрения непрофессионала, это будут «переменные типа». Этот тип переменной может использоваться при создании классов, интерфейсов и методов. Самый простой способ понять дженерики Java - это рассматривать его как удобный синтаксис, который может сэкономить вам некоторые операции на casting типа Java:
Список <pple> box = new ArrayList <pple> (); box.add (new Apple ()); Apple Apple = box.get (0);
Сам приведенный выше код четко выражен: Box - это List с Apple Objects. Метод get возвращает экземпляр объекта Apple, и этот процесс не требует преобразования типа. Нет никаких дженериков, приведенный выше код должен быть написан так:
Apple Apple = (Apple) Box.get (0);
Конечно, дженерики не так просты, как я описал здесь, но это не главный герой нашего дня. Студенты, которые не понимают дженериков очень хорошо, должны восполнить уроки ~ Конечно, лучшие справочные материалы по -прежнему остаются официальными документами.
2. Проблемы, вызванные дженериками (до Java 7)
Самым большим преимуществом дженериков является то, что они обеспечивают безопасность типа программы и могут быть обратно совместимыми. Тем не менее, есть и вещи, которые делают разработчиков несчастными. Тип дженериков должен быть написан каждый раз, когда они определяют. Эта спецификация дисплея не только кажется немного многослойной, но и, что наиболее важно, многие программисты не знакомы с дженеками, поэтому они не могут дать правильные параметры типа во многих случаях. Теперь компилятор автоматически делает типы дженериков параметров, что может уменьшить эту ситуацию и улучшить читаемость кода.
3. Улучшения в типовом выводе дженериков в Java 7
Использование общих типов в предыдущих версиях Java 7 требует добавления общих типов с обеих сторон при объявлении и назначении значений. Например:
Map <string, integer> map = new hashmap <string, integer> ();
Многие люди, должно быть, были такими же, как и я в начале, и они были озадачены этим: разве я не объявил тип параметра в объявлении переменной? Почему мне все еще нужно написать это, когда объект инициализирован? Это также заставляет дженерики жаловаться, когда они впервые появились. Тем не менее, приятно, что, хотя Java улучшается, дизайнеры также постоянно улучшают Java Compiler, чтобы сделать его более умным и гуманизированным. Вот наш главный герой сегодня: тип отжимания ... ну ... это не вывод типа, то есть тип вывод. Когда появляется этот парень, когда он пишет приведенный выше код, он может с радостью опустить типы параметров, когда создается экземпляр объекта, и это становится таким:
Map <string, integer> map = new hashmap <> ();
В этом утверждении компилятор автоматически выводит общий тип при создании HashMap на основе общего типа при объявлении переменной. Опять же, обязательно обратите внимание на «<>» за new HashMap . Только добавление этого «<>» означает, что это автоматический вывод типа, в противном случае это негенерический HashMap , и при составлении исходного кода будет предоставлена предупреждающая подсказка. Эта пара угловых кронштейнов «<>» называется «Diamond» в официальном документе.
Тем не менее, вывод типа в это время не является полным (даже полуфабрикативный продукт), потому что вывод типа при создании общих экземпляров в Java SE 7 ограничен: только если параметризованный тип конструктора значительно объявлен в контексте, может быть использован вывод типа, в противном случае он не будет работать. Например: следующий пример не может быть правильно скомпилирован в Java 7 (но теперь он может быть скомпилирован в Java 8, поскольку общий тип автоматически выводится на основе параметров метода):
List <string> list = new ArrayList <> (); list.add ("a"); // Поскольку Addall планирует получить параметры типа Collection <? Extends String>, следующее утверждение не может пройти список. Addall (new ArrayList <> ());4. Переоценка в Java 8
В последней официальной документации на Java мы можем увидеть определение деривации типа:
Вывод типа - это способность компилятора Java смотреть на каждый вызов метода и соответствующее объявление, чтобы определить аргумент типа (или аргументы), который делает применимый вызов. Алгоритм вывода определяет типы аргументов и, если таковые имеются, тип, который присваивается или возвращается результат. Наконец, алгоритм вывода пытается найти самый специфический тип, который работает со всеми аргументами.
Короче говоря, деривация типа относится к способности компилятора определять необходимые типы параметров на основе метода, который вы вызовы и соответствующее объявление. И пример также приведен в официальной документации, чтобы объяснить:
Статический <t> t pick (t a1, t a2) {return a2; } Serializable s = pick ("D", новый ArrayList <String> ()); Здесь компилятор может сделать вывод, что тип второго параметра, пройденного в методе pick является Serializable .
В предыдущих версиях Java, если приведенный выше пример может быть составлен, вам нужно написать это:
Serializable s = this. <serializable> pick ("d", новый ArrayList <string> ());Подробная причина для написания этого можно увидеть в общей главе «Программирующей мысли Брюса Экеля» (четвертое издание). Конечно, эта книга основана на Java 6, и эта версия не имеет концепции типа. Видя это, многие люди могут ясно видеть силу деривации типа в последней версии. Он больше не ограничивается процессом объявления и экземпляра общих классов, но распространяется на методы с общими параметрами.
4.1 Вывод типа и общие методы
Что касается вывода типа и общих методов в новой версии, документ также приводит немного более сложный пример. Я опубликовал это здесь. Принцип такой же, как и Serializable пример, поэтому я не буду вдаваться в подробности. Если вы хотите консолидировать его, вы можете посмотреть:
public Class boxdemo {public static <u> void addbox (u u, java.util.list <box <u >> boxes) {box <u> box = new Box <> (); box.set (u); Boxes.Add (Box); } public static <u> void outputboxes (java.util.list <box <u >> box) {int counter = 0; Для (Box <u> Box: Boxes) {u boxcontents = box.get (); System.out.println ("Box #" + counter + "содержит [" + boxcontents.tostring () + "]"); счетчик ++; }} public static void main (string [] args) {java.util.arraylist <box <Integer >> listofintegerboxes = new java.util.arraylist <> (); BoxDemo. <Integer> addbox (integer.valueof (10), listofintegerboxes); Boxdemo.addbox (integer.valueof (20), listofintegerboxes); Boxdemo.addbox (integer.valueof (30), listofintegerboxes); Boxdemo.outputboxes (listofintegerboxes); }}Вышеуказанный вывод кода:
Вставка № 0 содержит [10] Коробка № 1 содержит [20] Коробка № 2 содержит [30]
Позвольте мне упомянуть, что фокус общего метода addBox - это описание типа, которое вам больше не нужно отображать в вызове метода в новой версии Java, например:
BoxDemo. <Integer> addbox (integer.valueof (10), listofintegerboxes);
Компилятор может автоматически сделать вывод, что тип параметра является Integer из параметров, передаваемых в addBox .
4.2 Тип вывода и общие конструкторы общих и негенерических классов
Ну ... это может быть лучшим предложением на английском языке: вывод типа и общие конструкторы общих и негенерических классов
На самом деле, общие конструкторы не являются патентами для общих классов. Неполученные классы также могут иметь свои собственные универсальные конструкторы. Взгляните на этот пример:
класс myclass <x> {<t> myclass (t t) {// ...}}Если в классе MyClass будет сделано следующая экземпляра:
Новый MyClass <Integer> ("") ОК, здесь мы показываем, что тип параметра x myclass является Integer , и для конструктора компилятор выводит, что формальный параметр t является String на основе входящего String объекта (""). Это было реализовано в версии Java7. Какие улучшения были сделаны в Java8? После Java8 мы можем написать этот экземпляр общего класса с общим конструктором, как это:
Myclass <Integer> myobject = new myclass <> (""); Да, это все еще пара угловых кронштейнов (<>), которая называется Diamond, так что наш компилятор может автоматически вывести, что формальные параметры x являются Integer и t String . Это на самом деле очень похоже на наш первоначальный пример Map<String,String> , за исключением того, что существует общая конструктор.
Следует отметить, что деривация типа может быть получено только на основе типа параметров вызова, типа цели (это будет обсуждаться в ближайшее время) и типа возврата (если есть возврат), и не может быть получен на основе некоторых требований после программы.
4.3 Целевой тип
Как упоминалось ранее, компилятор может выполнять деривацию типа на основе целевого типа. Целевой тип выражения относится к правильному типу данных, который нужен компилятору на основе того, где появляется выражение. Например, этот пример:
static <t> list <t> emptylist (); list <string> listone = collections.emptylist ();
Здесь List <string> является целевым типом, потому что здесь необходимо List<String> и Collections.emptyList() возвращает List<T> , поэтому компилятор здесь делает здесь, что T должен быть String . Это нормально в Java 7 и 8. Однако в Java 7 это не может быть скомпилировано обычно в следующей ситуации:
void ProcessStringList (list <string> stringlist) {// Process StringList} ProcessStringList (collections.emptylist ());В настоящее время Java7 даст это сообщение об ошибке:
// список <object> не может быть преобразован в список <string>
Причина: Collections.emptyList() возвращает List<T> , а T здесь требует определенный тип, но поскольку он не может быть выведен из объявления метода, что то, что требуется, является String , компилятор дает t значение Object . Очевидно, что List<Object> не может быть преобразован в List<String>. Итак, в версии Java7 вам нужно назвать этот метод таким образом:
ProcessStringList (Collections. <string> emptyList ());
Однако в Java 8, из -за введения концепции Target Type, очевидно, что то, что нужно компилятору, является List<String> (то есть целевой тип здесь), поэтому компилятор делает, что T в возвращаемом List<T> должен быть String , поэтому описание processStringList(Collections.emptyList()); в порядке.
Использование целевых типов наиболее очевидно в выражениях Lambda.
Суммировать
ОК, вышеупомянутое личное понимание вывода типа в Java. Таким образом, все более совершенное вывод типа заключается в завершении некоторой работы по конверсии типа, которая кажется естественной, но все эти работы остаются для компилятора для автоматического вывода, а не для того, чтобы позволить разработчикам отображать его. Я надеюсь, что содержание этой статьи будет полезно для всех в изучении Java. Если у вас есть какие -либо вопросы, вы можете оставить сообщение для общения.