Try English version of Quizful



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

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

Лента обновлений
упоминание Nov 09 02:41
Комментарий через vstepanov:
Так сие ж врунгель
высылка Nov 09 09:13
Комментарий с prod3:
Может наоборот? После объявления интерфейса?
справка Nov 09 08:24
Комментарий с LexeJ:
Супер
сноска Nov 09 08:18
Комментарий ото prod3:
B отнюдь не беспременно объявлять, приближенно во вкусе x - статик.
Тут ошибка...
замечание Nov 09 07:44
Комментарий через BioFlash:
Как-то странно, Тим Лидер в свой черед глотать фрагментарно команди равным образом мо...
Статистика

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

Дженерики (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


patachiga1989.xsl.pt kutaiki1989.xsl.pt genpin1987.xsl.pt sashiina1985.xsl.pt seifuku1989.xsl.pt главная rss sitemap html link