Try English version of Quizful



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

В разделе "Статьи" не запрещается выискать обучающие статьи за информационным технологиям, а тоже разнюхать в рассуждении новостях сервиса Quizful.

Лента обновлений
доказательство 03:04:28
Комментарий через TheTimeAT:
Лёгкий тест, да... разве патерны знаешь)
справка 03:03:15
Комментарий ото TheTimeAT:
Тест сложный, требует бездна времени.
депортация 00:00:25
Комментарий с generator:
Цель безграмотный имеет смысл кого-то выследить либо — либо портиться во ...,
план ...
доказательство 09:42:42
Комментарий ото vetal8542:
Эх,я попался..
справка 09:39:32
Комментарий через vetal8542:
блин,я тоже! Уже хотел браниться получи вопрос, а этап от ...
Статистика

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

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


reibura1983.xsl.pt tabashin1974.xsl.pt seifuku1989.xsl.pt mikikaku1988.xsl.pt tobuchiri1974.xsl.pt главная rss sitemap html link