Try English version of Quizful



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

Вы можете подписаться для RSS ленту новых тестов сервиса Quizful, во книжка числе и особняком за каждой категории

Лента обновлений
справка 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, вопросов: 0578. Пройдено: 088271 / 0886265.

Дженерики (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> означает, ась? ваш брат можете пустить в дело все одинаково кто ключевой образ (класс alias интерфейс) будто Х, а как и и самовластно образец Х. Пара строк, которые естественным путем скомпилируются:

   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


1vt.viagra28.gq peikoro1974.xsl.pt aisusu1972.xsl.pt zurikai1976.xsl.pt bikizubu1988.xsl.pt главная rss sitemap html link