Try English version of Quizful



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

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

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

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

Дженерики (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 (дженерики) alias <<контейнеры вроде 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


andresw0708.dns.navy www23.www7.viagra28.cf yzambre1308.zone-ip.top prvanessa1208.hello-ip.eu wqamari0708.godrejseethru.com главная rss sitemap html link