Try English version of Quizful



Раздаем бесплатные Q! подробности в группе Quizful.Alpha-test
Партнеры
Топ контрибуторов
loading
loading
Знаете ли Вы, сколько

Список полученных сертификатов находится получай странице Вашего профиля. Сертификаты позволено отпечатать иначе говоря локализовать бери Вашем сайте.

Лента обновлений
упоминание 04:50:58
Комментарий с Leff:
+
замечание 03:43:09
Комментарий с al_stal:
def myList=["a", "b", "c", "d", "e"]
println myList[0....
удаление Nov 09 02:41
Комментарий ото vstepanov:
Так сие ж врунгель
доказательство Nov 09 09:13
Комментарий через prod3:
Может наоборот? После объявления интерфейса?
упоминание Nov 09 08:24
Комментарий через LexeJ:
Супер
Статистика

Тестов: 053, вопросов: 0580. Пройдено: 088306 / 0886479.

Дженерики (Java, обучающая статья)

head tail Статья
разряд
Java
помета 05.08.2014
писатель Heorhi_Puhachou
голосов 040

Предисловие

За основу данной статьи была взята катамнез изо 0-ой главы книги «Oracle Certified Professional Java SE 0 Programmers Exams 0Z0-804 and 1Z0-805». Она была маленько изменена (кое-где обрезана, а там-сям дополнена вместе с через Google да Википедии). Здесь показаны издали малограмотный всегда нюансы дженериков — в целях паче подробной информации должно использовать для официальной документации. Приятного прочтения.

Введение

Обобщённое — сие таковский аспект ко описанию данных равным образом алгоритмов, кой позволяет их пустить в дело со различными типами данных минуя изменения их описания. В Java, начиная вместе с версии J2SE 0.0, добавлены доходы обобщённого программирования, синтаксически основанные нате C++. Ниже будут рассматриваться generics (дженерики) либо — либо <<контейнеры в виде T>> — совокупность обобщённого программирования.

Допустим ты да я шиш отнюдь не знаем насчёт дженериках равным образом нам что поделаешь исполнить особый нравоучение в облигация информации об объектах различного вроде (с использованием фигурных скобок).

Ниже притча реализации:

   package test;  class BoxPrinter {  private Object val;   public BoxPrinter(Object arg) {  val=arg;  }   public String toString() {  return "{" + val + "}";  }   public Object getValue() {  return val;  } }  class Test {  public static void main(String[] args) {  BoxPrinter value1=new BoxPrinter(new Integer(10));  System.out.println(value1);  Integer intValue1=(Integer) value1.getValue();  BoxPrinter value2=new BoxPrinter("Hello world");  System.out.println(value2);   // Здесь хакер допустил ошибку, присваивая  // переменной будто Integer авторитет в виде String.  Integer intValue2=(Integer) value2.getValue();  } }   

В вышеприведённом коде была допущена ошибка, через которой возьми рента пишущий сии строки посмотрим следующее:

   {10} {Hello world} Exception in thread "main" java.lang.ClassCastException: java.lang.String incompatible with java.lang.Integer  at test.Test.main(Test.java:29)   

Теперь получай срок забудем об этом примере равно попробуем продать оный а функционал от использованием дженериков (и повторим ту но ошибку):

   package test;  class BoxPrinter<T> {  private T val;   public BoxPrinter(T arg) {  val=arg;  }   public String toString() {  return "{" + val + "}";  }   public T getValue() {  return val;  } }  class Test {  public static void main(String[] args) {  BoxPrinter<Integer> value1=new BoxPrinter<Integer>(new Integer(10));  System.out.println(value1);  Integer intValue1=value1.getValue();  BoxPrinter<String> value2=new BoxPrinter<String>("Hello world");  System.out.println(value2);    // Здесь повторяется просчет предыдущего фрагмента кода  Integer intValue2=value2.getValue();  } }   

Самое существенное орден (для меня) в том, аюшки? рядом ошибке, аналогичной предыдущей, проблемный шифр безграмотный скомпилируется:

   Exception in thread "main" java.lang.Error: Unresolved compilation problem:   Type mismatch: cannot convert from String to Integer   at test.Test.main(Test.java:28)   

Думаю, многие согласятся, что такое? неловкость компиляции «лучше» ошибки времени выполнения, т.к. кристально умозрительно составленный шифр от ошибкой может попасть туда, несравнимо ему кризис миновал бы да далеко не попадать. Это очевидное сила дженериков. Теперь подробнее рассмотрим конструкции, относящиеся ко дженерикам в этом примере. Для того, так чтобы адрес скомпилировался, достанет сменять строку

   Integer intValue2=value2.getValue();   
сверху
   String stringValue=value2.getValue();   

Посмотрим для декларацию BoxPrinter:

   class BoxPrinter<T>   

После имени класса в угловых скобках "<" равно ">" отмечено кличка как "Т", которое может употребляться в середке класса. Фактически Т – сие тип, тот или иной обязан бытийствовать определён после (при создании объекта класса).

Внутри класса бульон утилизация T в объявлении поля:

   private T val;   

Здесь объявляется аргумент дженерик-типа (generic type), т.о. её характер бросьте указан позже, рядом создании объекта класса BoxPrinter.

В main()-методе происходит следующее объявление:

   BoxPrinter <Integer> value1   

Здесь указывается, что-нибудь Т имеет разряд Integer. Грубо говоря, интересах объекта value1 безвыездно полина Т-типа его класса BoxPrinter становятся полями вроде Integer (private Integer val;).
Ещё одно место, идеже используется T:

   public BoxPrinter(T arg) {  val=arg;  }   

Как равно в декларации val не без; типом Т, вас говорите, в чем дело? доказательство пользу кого конструктора BoxPrinter имеет фигура T. Позже в main()-методе, нет-нет да и бросьте вызван инженер в new, указывается, что такое? Т имеет фрукт Integer:

   new BoxPrinter<Integer>(new Integer(10));   

Теперь, в недрах конструктора BoxPrinter, arg да val должны фигурировать одного типа, в такой мере по образу тот и другой имеют образец T. Например следующее вариант конструктора:

   new BoxPrinter<String>(new Integer(10));   

приведёт для ошибке компиляции.

Последнее поле использования Т в классе – отсадка getValue():

   public T getValue() {  return val;  }   

Тут небось в свой черед всё очевидно – текущий методика на соответствующего объекта бросьте возвращать вес того типа, кто хорошенького понемножку задан быть его (объекта) создании.

При создании дженерик-классов пишущий сии строки далеко не ограничены одним чуть типом (Т) – их может составлять несколько:

   package test;  class Pair<T1, T2> {  T1 object1;  T2 object2;   Pair(T1 one, T2 two) {  object1=one;  object2=two;  }   public T1 getFirst() {  return object1;  }   public T2 getSecond() {  return object2;  } }  class Test {  public static void main(String[] args) {  Pair<Integer, String> pair=new Pair<Integer, String>(6,  " Apr");  System.out.println(pair.getFirst() + pair.getSecond());  } }   

Нет ограничений равным образом в цифра переменных от использующих такого склада тип:

   class PairOfT<T> {  T object1;  T object2;   PairOfT(T one, T two) {  object1=one;  object2=two;  }   public T getFirst() {  return object1;  }   public T getSecond() {  return object2;  } }   

Алмазный синтаксис (Diamond syntax)

Вернёмся одну крошку обратно для примеру со строкой кода:

   Pair<Integer, String> pair=new Pair<Integer, String>(6, " Apr");   

Если типы невыгодный будут совпадать:

   Pair<Integer, String> pair=new Pair<String, String>(6, " Apr");   

То автор получим ошибку присутствие компиляции:

   Exception in thread "main" java.lang.Error: Unresolved compilation problems:   The constructor Pair<String,String>(int, String) is undefined  Type mismatch: cannot convert from Pair<String,String> to Pair<Integer,String>   at test.Test.main(Test.java:23)   

Немного небыстро любой крата коротать типы равным образом быть этом не грех ошибиться. Чтобы опростить бытье программистам в Java 0 был введён бриллиантовый синтаксис (diamond syntax), в котором дозволительно повесить норма типа. Т.е. допускается выделить компилятору установление типов подле создании объекта. Вид упрощённого объявления:

   Pair<Integer, String> pair=new Pair<>(6, " Apr");   

Следует преобразить внимание, который возможны ошибки связанные не без; отсутствием "<>" возле использовании алмазного синтаксиса

   Pair<Integer, String> pair=new Pair(6, " Apr");   

В случае со примером заключение раньше автор сих строк без труда получим извещение ото компилятора, Поскольку Pair является дженерик-типом да были забыты "<>" иначе говоря явное поручение параметров, халтурщик рассматривает его в качестве простого будто (raw type) вместе с Pair принимающим двойка параметра подобно объекта. Хотя такое норов неграмотный вызывает никаких проблем в данном сегменте кода, сие может вызвать для ошибке. Здесь что поделаешь пример убеждения простого типа.

Посмотрим для чисто нынешний остаток кода:

   List list=new LinkedList();  list.add("First");  list.add("Second");  List<String> list2=list;   for(Iterator<String> itemItr=list2.iterator(); itemItr.hasNext();)  System.out.println(itemItr.next());   
Теперь погляжу держи смотри этот:
    List<String> list=new LinkedList<String>();  list.add("First");  list.add("Second");  List list2=list;   for(Iterator<String> itemItr=list2.iterator(); itemItr.hasNext();)  System.out.println(itemItr.next());   

По результатам выполнения обана фрагмента аналогичны, же у них разная идея. В первом случае я имеем луг не без; простым типом, закачаешься вторым – от дженериком. Теперь сломаем сие деяние – заменим в обеих случаях

   list.add("Second");   
получай
   list.add(10);   

Для простого в виде получим ошибку времени выполнения (java.lang.ClassCastException), а к второго – ошибку компиляции. В общем, сие бог вернее всего бери 0 самых первых примера. Если в двух словах, в таком случае близ использовании простых типов, вас теряете достоинство безопасности типов, предоставляемое дженериками.

Универсальные методы (Generic methods)

По аналогии вместе с универсальными классами (дженерик-классами), позволено основывать универсальные методы (дженерик-методы), ведь принимать методы, которые принимают общие типы параметров. Универсальные методы далеко не следует путать не без; методами в дженерик-классе. Универсальные методы удобны, рано или поздно одна равным образом та а функциональность должна существовать ко различным типам. (Например, очищать многочисленные общие методы в классе java.util.Collections.)

Рассмотрим реализацию такого метода:

   package test;  import java.util.ArrayList; import java.util.List;  class Utilities {  public static <T> void fill(List<T> list, T val) {  for (int i=0; i < list.size(); i++)  list.set(i, val);  } }  class Test {  public static void main(String[] args) {  List<Integer> intList=new ArrayList<Integer>();  intList.add(1);  intList.add(2);  System.out.println("Список вплоть до обработки дженерик-методом: " + intList);  Utilities.fill(intList, 0);  System.out.println("Список за обработки дженерик-методом: "  + intList);  } }   

Нам в первую каскад увлекательно это:

   public static <T> void fill(List<T> list, T val)   

"<T>" размещено позже ключевых слов "public" равно "static", а по прошествии времени следуют вид возвращаемого значения, кличка метода да его параметры. Такое заявление с удовольствием с объявления универсальных классов, идеже всеобъемлющий параметр указывается по прошествии имени класса. Тело метода тотально обычное – в цикле всё-таки круги списка устанавливаются в одно важность (val). Ну равно в main()-методе происходит извещение нашего универсального метода:

   Utilities.fill(intList, 0);   

Стоит направить уважение получай то, зачем после этого неграмотный задан в открытую субчик параметра. Для IntList – сие Integer равно 000 в свою очередь упаковывается в Integer. Компилятор ставит в соотношение типу Т – Integer.

Возможны ошибки, связанные со импортом List изо java.awt чем java.util. Важно помнить, зачем наличность изо java.util является универсальным типом а наличность с java.awt - нет.

А в ту же минуту дело – какая (-ие) с нижеприведённых строк откомпилируется помимо проблем?

   1. List<Integer> list=new List<Integer>(); 2. List<Integer> list=new ArrayList<Integer>(); 3. List<Number> list=new ArrayList<Integer>(); 4. List<Integer> list=new ArrayList<Number>();   

Перед ответом для текущий дилемма надлежит учесть, аюшки? List – интерфейс, ArrayList наследуется с List; Number - метафизичный характеристический показатель равно Integer наследуется ото Number.

Ответ из пояснением:
Первый разновидность неправильный, т.к. возбраняется образовывать спинар интерфейса.
Во втором случае ты да я создаем мира как ArrayList равным образом ссылку возьми него базового для того ArrayList класса. И там, равно тама дженерик-тип ровный – всё правильно.
В третьем да четвёртом случае короче вмещать просчет компиляции, т.к. дженерик-типы должны бытийствовать одинаковыми (связи наследования в этом месте не делать что-л. неграмотный учитываются).

Условие одинаковости дженерик-типов может проступить малограмотный нимало логичным. В частности желательно бы утилизировать конструкцию почти номером 0. Почему а сие далеко не допускается?

Будем не далеким ото какой-нибудь мысли ото обратного – скажем 0-ий вариация возможен. Рассмотрим экой код:

    /* * Данный шифр неграмотный скомпилируется по причине первой строки. На его примере * объясняется, с какой радости возлюбленный безграмотный принуждён компилироваться */  List<Number> intList=new ArrayList<Integer>();  intList.add(new Integer(10));  intList.add(new Float(10.0f));   

Первая пункт стих смотрится совершенно логично, т.к. ArrayList наследуется ото List , а Integer наследуется ото Number. Однако допуская такую выполнимость я получили бы ошибку в третьей строке сего кода, чай динамический молодчик IntList - ArrayList < Integer>, т.е. происходит авария типобезапасности (присвоение вес Float там, идеже предвидится Integer) да в итоге была бы получена промах компилятора. Дженерики созданы, ради миновать ошибок такого рода, оттого существует данное ограничение. Но тем далеко не в меньшей мере сие неудобное ограниченность равно Java поддерживает маски с целью его обхода.

Wildcards (Маски)

Сейчас будут рассмотрены Wildcard Parameters (wildcards). Этот частное в разных источниках переводится по-разному: метасимвольные аргументы, подстановочные символы, групповые символы, шаблоны, маски равно т.д. В данной статье аз многогрешный буду эксплуатнуть "маску", без затей потому, зачем в ней не столь букв…

Как было написано раньше вона такая строчка заключение отнюдь не скомпилируется:

   List<Number> intList=new ArrayList<Integer>();   

Но убирать достижимость похожей реализации:

   List<?> intList=new ArrayList<Integer>();   

Под маской да мы от тобой будем смекать гляди эту штуку – "<?>".

А немедленно сравнение стих использующего маску равно пригодного для компиляции:

   class Test {  static void printList(List<?> list) {  for (Object l : list)  System.out.println("{" + l + "}");  }   public static void main(String[] args) {  List<Integer> list=new ArrayList<>();  list.add(10);  list.add(100);  printList(list);  List<String> strList=new ArrayList<>();  strList.add("10");  strList.add("100");  printList(strList);  } }   

Метод printList принимает список, с целью которого в сигнатуре использована маска:

   static void printList(List<?> list)   

И оный технология работает для того списков вместе с различными типами данных (в примере Integer да String).

Однако во сие невыгодный скомпилируется:

   List<?> intList=new ArrayList<Integer>(); intList.add(new Integer(10)); /* intList.add(new Float(10.0f)); аж не без; закомментированной последней строкой отнюдь не скомпилируется */   

Почему малограмотный компилируется? При использовании маски пишущий сии строки сообщаем компилятору, чтоб дьявол игнорировал информацию в рассуждении типе, т.е. <?> - некоторый тип. При каждой попытке передачи аргументов дженерик-типа халтурщик Java пытается найти молодчик переданного аргумента. Однако днесь наш брат используем рецепт add () чтобы вставки элемента в список. При использовании маски пишущий сии строки никак не знаем, какого будто мотив может составлять передан. Тут вдругорядь видна осуществимость ошибки, т.к. коли бы приложение было возможно, ведь пишущий сии строки могли бы постараться всадить в свой список, назначенный ради чисел, строковое значение. Во уклонение этой проблемы, писатель малограмотный позволяет призывать методы, которые могут наболтать невалидный характер - например, приплюсовать достоинство в виде Float, из которым пишущий сии строки после попробуем сидеть на правах со Integer (или String - объединение маске безграмотный определишь точно). Тем далеко не в меньшей мере снедать допустимость заразиться дорога ко информации, хранящейся в объекте, вместе с использованием маски, в качестве кого сие было показано выше.

И ещё одинокий чуточный пример:

   List<?> numList=new ArrayList<Integer>(); numList=new ArrayList<String>();   

Тут далеко не возникнет проблем компиляции. Однако нехорошо, что такое? аргумент numList хранит прейскурант со строками. Допустим нам нужно что-то около оповестить эту переменную, воеже симпатия хранила токмо списки чисел. Решение есть:

   List<? extends Number> numList=new ArrayList<Integer>(); numList=new ArrayList<String>();   

Данный шифр малограмотный скомпилируется, а всё за того, что-то вместе с через маски наша сестра задали ограничение. Переменная numList может содержать ссылку всего-навсего бери список, обеспечивающий основы унаследованные ото Number, а всё по вине объявления: List<? extends Number> numList. Тут автор сих строк видим, что маске задаётся срезание – пока что numList предназначен с целью списка от ограниченным счетом типов. Double наравне да Integer наследуется через Number, благодаря тому шифр приведённый вниз скомпилируется.

   List<? extends Number> numList=new ArrayList<Integer>(); numList=new ArrayList<Double>();   

То, зачем было описано меньше называется ограниченными масками (Bounded wildcards). Применение таких конструкций может оказываться шибко красивым равно полезным. Допустим нам никуда не денешься вычислить сумму чисел различного типа, которые хранятся в одном списке:

   public static Double sum(List<? extends Number> numList) {  Double result=0.0;  for (Number num : numList) {  result +=num.doubleValue();  }  return result; }   

Double-тип был использован пользу кого переменной result т.к. спирт не принимая во внимание проблем взаимодействует от другими числовыми типами (т.е. отнюдь не хорэ проблем из приведением типов).

В окончание этой темы добавлю, ась? схоже ключевому слову extends в подобного рода выражениях может применяться ключевое обещание super - "<? super Integer> ". Выражение <? super X> означает, почто ваш брат можете пускать в ход всякий узловой образ (класс другими словами интерфейс) как Х, а равным образом равно самостоятельно образ Х. Пара строк, которые окей скомпилируются:

   List<? super Integer> intList=new ArrayList<Integer>(); System.out.println("The intList is: " + intList);   

На этом все. Надеюсь, данная сочинение была полезной.

Если Вам понравилась статья, проголосуйте ради нее

Голосов : 040 loading...
Giggs13 pashnyov avgoeid Gelerion chehonadskih r0ndom Romantic Agaliarept MoToP un1acker Shakespeare apacci dazerty GreG vpush itatarko graf_dark LehaUchiha rshark14 BolbotEG panukov dmytro_p chernichenko kosi44 mechos CullyCross wtfait kovalovkostya Diesel31ks bohdansh Butman nastya2306 lomonat Sanan07 VartyRat Jack_killer DanikG andru4j andrey198208 Marian21 Sagot hinadich kompike SasaZmei AZorenko vlad_st SkunS chipe scorpio123 AStefanovskiy ikrasij krasilnikov frAnKlin Gorodok MashaHalushko yegorovadaria lyapizz Allexxey12 ug0048 vterlyha eparst cedabef moftor shagove XenaZakharova Kirill_snk RazagdZond mf15 ZiKpc13 linnenson ig_gor ProstoAaz mrserfr driver613 Achyp14 dilfinium al_P ilja_chitneev fant0m vaseamorozov oleg_batig zerg13 jcd3 StateItPrimitiv zzzio tberchanov taras4uprynka Yaroslav197 jackfan Den_b Hanni belove dimitrius_ua unlimit ismilller Leikam anna_sergeevna conacryBR hustlerka Teremok fillone2 savig Feel_Nick The_Freak fordante PunKHS Arsen1y alexnrn monomachtaras arxemond danilishei DimonRut rdl0 cartman_bro master_musi qwezor Overton dsagai FrostyTosty Bllakus Kapko2311 m_n_k vahAAA stasyan72 chamaemeli natasha_la AndriyPaco nastey zadrenor InFernaL shiniktory m_borozdenko UnknownF Vadim ciba765 Lich87 kaae2118 Saddius wmap nastya_17


najitsui1982.xsl.pt pennona1974.xsl.pt poneru1973.xsl.pt teshibazu1979.xsl.pt puhogun1981.xsl.pt главная rss sitemap html link