Главная страница
Навигация по странице:

  • 2. Для чего нужны дженерики

  • 3. Что такое сырые типы (raw type)

  • 4. Что такое вайлдкарды (Маски)

  • 5. Расскажите про принцип PECS

  • Пример: метод copy () в классе Collectors

  • 8. Коллекции 1. Что такое «коллекция»

  • 2. Расскажите про иерархию коллекций

  • 3. Почему Map — это не Collection, в то время как List и Set являются Collection

  • 4. В чем разница между классами java.util.Collection и java.util.Collections

  • 5. Какая разница между итераторами с fail-fast и fail-safe поведением (С примерами)

  • 6. Чем различаются Enumeration (устаревший) и Iterator

  • 7. Как между собой связаны Iterable, Iterator и «for-each»

  • 8. Можно ли итерируясь по ArrayList удалить элемент Какое вылетит исключение

  • 9. Как поведёт себя коллекция, если вызвать iterator.remove()

  • 10. Чем Set отличается от List

  • 11. Расскажите про интерфейс Set.

  • 1. Что такое дженерики


    Скачать 0.84 Mb.
    Название1. Что такое дженерики
    АнкорCore-2
    Дата23.03.2022
    Размер0.84 Mb.
    Формат файлаpdf
    Имя файла02_CORE_2-1.pdf
    ТипДокументы
    #410542
    страница1 из 5
      1   2   3   4   5

    7. Дженерики
    1. Что такое дженерики?
    Generics - набор свойств языка позволяющих определять и использовать обобщенные типы и методы.
    Обобщенные типы или методы отличаются от обычных тем, что имеют типизированные параметры (T – параметр в котором могут быть разные объекты).
    ArrayList list = new ArrayList();
    Свойства Generics:
    -
    Строгая типизация.
    -
    Единая реализация.
    -
    Отсутствие информации о типе.
    Ограничения:
    - - в <> могут быть только ссылочные типы, можно String, Integer, int [] array, int, double, 10;
    - - внутри класса или метода нельзя создать экземпляр класса, массив или использовать метод equals, так как внутри класса не известно о самом классе – компилятор не может понять тип
    - ограничение наследования
    Пусть у нас есть тип Foo, который является подтипом Bar, и еще G - наследник Коллекции.
    То G не является наследником G.
    - не может быть параметром статического класса
    - Не может Создать, Поймать, или Бросить Объекты Параметризованных Типов class MathException extends Exception { /* ... */ } // compile-time error
    - У class не может быть двух перегруженных методов, у которых будет та же самая подпись после стирания типа. public class Example { public void print(Set strSet) { } public void print(Set intSet) { }
    }
    Примером использования обобщенных типов может служить Java Collection Framework. Так, класс
    LinkedList - типичный обобщенный тип. Он содержит параметр E, который представляет тип элементов, которые будут храниться в коллекции. Создание объектов обобщенных типов происходит посредством замены параметризированных типов реальными типами данных. Вместо того, чтобы просто использовать
    LinkedList, ничего не говоря о типе элемента в списке, предлагается использовать точное указание типа
    LinkedList, LinkedList и т.п.
    2. Для чего нужны дженерики?
    Позволяет осуществлять проверку на правильность написания кода во время компиляции, а не в
    Runtime. Возможность создавать универсальные алгоритмы и структуры данных.
    Сделали использование Java Collection Framework проще, удобнее и безопаснее
    С их помощью можно объявлять классы, интерфейсы и методы, где тип данных указан в виде параметра. generics (обобщенные типы и методы) позволяют нам уйти от жесткого определения используемых типов.
    Компилятор стирает все дженерики. В Runtime дженериков практически нет. Компилятор использует кастование
    3. Что такое сырые типы (raw type)?
    Сырые типы — это типы без указания "уточненения" в фигурных скобках.
    Нужны чтобы поддерживать старый код (обратная совместимость). Рекомендуется использовать хоть какие-то параметризованные типы.
    Raw type - это имя интерфейса без указания параметризованного типа:
    Также Diamond синтаксис связан с понятием "Type Inference", или же выведение типов. Ведь компилятор, видя справа <> смотрит на левую часть, где расположено объявление типа переменной, в
    которую присваивается значение. И по этой части понимает, каким типом типизируется значение справа.
    List list = new ArrayList<>();
    На самом деле, если в левой части указан дженерик, а справа не указан <>, компилятор сможет вывести тип.
    Однако это будет смешиванием нового стиля с дженериками и старого стиля без них - вы теряете безопасность (
    типобезопасность)
    типов (может добавляться какой угодно тип в список, а не то что надо. Когда будет доставаться – то может быть сюрприз)))
    ArrayList strings = new ArrayList<>(); // parameterized type
    ArrayList arrayList = new ArrayList(); //
    raw type arrayList = strings; // Ok strings = arrayList; // Unchecked assignment (назначение) arrayList.add(1); //unchecked call
    4. Что такое вайлдкарды (Маски)?
    Языковая конструкция внутри даймонд-оператора, позволяющая сделать код более универсальным.
    Решает проблему наследования типов в дженериках. (коллекция <Интежер> не наследник коллекции
    <Намбер>)
    Может быть 3-х типов: инвариантность, аппер и ловер
    Class: Cat / Dog -> Pet -> Animal -> Object
    - тип ? является любой наследник Animal (Upper Bounded (ограничение сверху)
    Wildcards)
    - тип ? является любой родитель Cat, включая Cat (Lower Bounded Wildcards). Dog не подходит.
    List numberList = new ArrayList<>();
    List integerList = new ArrayList<>(); numberList = integerList; integerList.add(5); // норм numberList.add(5); // ошибка компиляции public void process (List list){ list.add(5L); // ошибка компиляции
    }
    Означает, что мы можем присвоить в numberList листы
    : new ArrayList // это компилятор не видит new ArrayList // не видит
    Не положить туда Number и наследники, а присвоить!!
    Туда безопасно можем положить только null.
    Компилятор стирает дженерик типы и видит List.
    Т.е. безопасно будет:
    List numberList = new Number<>();
    Компилятор видит будещее, что если мы положим в list Лонг, а затем можем положить туда Интежер – будет не безопасно. Он кладет только то, что безопасно – null
    List numberList = new
    ArrayList<>();
    // можно ложить в лист Интежер, Лонг и т.п., нельзя Обжект
    Компилятор видит будущее, мы можем присвоить сюда Листы Намберов и Обжектов.
    Если мы положим в Лист Намберов Интежер,
    Лонг, Дабл – то ошибки не будет, а если положить туда Обжект – ошибка компиляции
    5. Расскажите про принцип PECS
    The Get and Put Principle или PECS (Producer Extends Consumer Super) Get and Put Principe
    Из одного типа переменных можно только читать, в другой — только вписывать (исключением является возможность записать null для extends и прочитать Object для super).
    -
    Запись вида Collection равносильна Collection , а значит — коллекция может содержать объекты любого класса, так как все классы в Java наследуются от Object – поэтому подстановка называется неограниченной.
    -
    Ковариация - Если мы объявили wildcard с extends, то это producer. Он только «продюсирует», предоставляет элемент из контейнера, а сам ничего не принимает.

    -
    Контрвариация - Если же мы объявили wildcard с super — то это consumer. Он только принимает, а предоставить ничего не может.
    Если метод имеет аргументы с параметризованным типом (например, Collection или Predicate), то в случае, если аргумент - производитель (producer), нужно использовать ? extends T, а если аргумент - потребитель (consumer), нужно использовать ? super T.
    Eсли метод читает данные из аргумента, то этот аргумент - производитель,
    Метод передаёт данные в аргумент, то аргумент является потребителем. Важно заметить, что определяя производителя или потребителя, мы рассматриваем только данные типа T.
    // Ковариантность, значит producer - аргумент nums отдает (производит) в метод ресурсы public static double sum(CollectionNumber> nums) { double s = 0.0; for (Number num : nums) s += num.doubleValue(); return s;}
    Listints = Arrays.asList(1,2,3); assert sum(ints) == 6.0; // Integer наследник Nums
    Listdoubles = Arrays.asList(2.78,3.14); assert sum(doubles) == 5.92;
    Listnums =
    Arrays.asList(1,2,2.78,3.14); assert sum(nums) == 8.92;
    //Контрвариантность - если аргумент метода потребляет в методе что-то
    /(возможно, изменяется сам) public static void count(CollectionInteger> ints, int n) { for (int i = 0; i < n; i++) ints.add(i);
    }
    Listints = new ArrayList(); count(ints, 5); assert ints.toString().equals("[0, 1, 2, 3, 4]");
    Listnums = new ArrayList(); count(nums, 5); nums.add(5.0); assert nums.toString().equals("[0, 1, 2, 3, 4, 5.0]");
    Listobjs = new ArrayList(); count(objs, 5); objs.add("five"); assert objs.toString().equals("[0, 1, 2, 3, 4, five]");
    Пример: метод copy () в классе Collectors
    Ковариантность — это сохранение иерархии наследования исходных типов в производных типах в том же порядке
    Множество<Животные> = Множество<Кошки>
    Контравариантность — это обращение иерархии исходных типов на противоположную в производных типах
    Множество<Кошки> = Множество<Животные>
    Инвариантность — отсутствие наследования между производными типами.
    8. Коллекции
    1. Что такое «коллекция»?
    «Коллекция» - это структура данных, набор каких-либо объектов. Данными (объектами в наборе) могут быть числа, строки, объекты пользовательских классов и т.п.
    Коллекции (java) – набор классов и интерфейсов, предназначенных для хранения данных. Каждый класс имеет свою специфику хранения объектов. Классы коллекций являются дженерик-параметрами.
    2. Расскажите про иерархию коллекций

    Интерфейс Collection расширяют интерфейсы:
    • List (список) представляет собой коллекцию, в которой допустимы дублирующие значения.
    Элементы такой коллекции пронумерованы, начиная от нуля, к ним можно обратиться по индексу.
    Реализации: o ArrayList - инкапсулирует в себе обычный массив, длина которого автоматически увеличивается при добавлении новых элементов. o LinkedList (двунаправленный связный список) - состоит из узлов, каждый из которых содержит как собственно данные, так и две ссылки на следующий и предыдущий узел. o Vector — реализация динамического массива объектов, методы которой синхронизированы
    (доступны по очереди, т.е. может использовать кто-то один). o Stack — реализация стека LIFO (last-in-first-out).
    • Set (сет) описывает неупорядоченную коллекцию, не содержащую повторяющихся элементов.
    Реализации: o HashSet - использует HashMap для хранения данных. В качестве ключа и значения используется добавляемый элемент. Из-за особенностей реализации порядок элементов не гарантируется при добавлении. o LinkedHashSet — гарантирует, что порядок элементов при обходе коллекции будет идентичен порядку добавления элементов. o (SortedSet) TreeSet — предоставляет возможность управлять порядком элементов в коллекции при помощи объекта Comparator, либо сохраняет элементы с использованием
    «natural ordering».
    • Queue (очередь) предназначена для хранения элементов с предопределённым способом вставки и извлечения FIFO (first-in-first-out): o PriorityQueue — предоставляет возможность управлять порядком элементов в коллекции при помощи объекта Comparator, либо сохраняет элементы с использованием «natural ordering». o ArrayDeque — реализация интерфейса Deque, который расширяет интерфейс Queue методами, позволяющими реализовать конструкцию вида LIFO (last-in- first-out).
    Интерфейс Map реализован классами:
    • Hashtable — хэш-таблица, методы которой синхронизированы. Не позволяет использовать null в качестве значения или ключа и не является упорядоченной.
    • HashMap — хэш-таблица. Позволяет использовать null в качестве значения или ключа и не является упорядоченной.
    • LinkedHashMap — упорядоченная реализация хэш-таблицы.
    • TreeMap — реализация, основанная на красно-чёрных деревьях. Является упорядоченной и предоставляет возможность управлять порядком элементов в коллекции при помощи объекта Comparator, либо сохраняет элементы с использованием «natural ordering».

    • WeakHashMap — реализация хэш-таблицы, которая организована с использованием weak references для ключей (сборщик мусора автоматически удалит элемент из коллекции при следующей сборке мусора, если на ключ этого элемента нет жёстких ссылок).
    3. Почему Map — это не Collection, в то время как List и Set являются Collection?
    Collection представляет собой совокупность некоторых элементов. Map - это совокупность пар «ключ- значение».
    4. В чем разница между классами java.util.Collection и java.util.Collections?
    Collections - набор статических методов для работы с коллекциями.
    Collection - один из основных интерфейсов Java Collections Framework
    5. Какая разница между итераторами с fail-fast и fail-safe поведением? (С примерами)
    fail-fast поведение означает, что при возникновении ошибки или состояния, которое может привести к ошибке, система немедленно прекращает дальнейшую работу и уведомляет об этом. Использование fail-fast подхода позволяет избежать недетерминированного поведения программы в течение времени.
    В Java Collections API некоторые итераторы ведут себя как fail-fast и выбрасывают
    ConcurrentModificationException, если после его создания была произведена модификация коллекции, т.е. добавлен или удален элемент напрямую из коллекции, а не используя методы итератора.
    Реализация такого поведения осуществляется за счет подсчета количества модификаций коллекции
    (modification count):
    - при изменении коллекции счетчик модификаций так же изменяется;
    - при создании итератора ему передается текущее значение счетчика;
    - при каждом обращении к итератору сохраненное значение счетчика сравнивается с текущим, и, если они не совпадают, возникает исключение.
    Итераторы по умолчанию для Collections из java.util package , такие как ArrayList , HashMap и т. д.,
    Являются Fail-Fast
    ArrayList numbers =//...
    Iterator iterator = numbers.iterator(); while (iterator.hasNext()) {
    Integer number = iterator.next(); numbers.add(50);
    }
    В приведенном выше фрагменте кода ConcurrentModificationException генерируется в начале следующего цикла итерации после выполнения модификации.
    итераторы fail-safe не вызывают никаких исключений при изменении структуры, потому что они работают с клоном коллекции вместо оригинала.
    Итератор коллекции CopyOnWriteArrayList и итератор представления keySet коллекции
    ConcurrentHashMap являются примерами итераторов fail-safe.
    6. Чем различаются Enumeration (устаревший) и Iterator?
    Хотя оба интерфейса и предназначены для обхода коллекций между ними имеются существенные различия:
    - с помощью Enumeration нельзя добавлять/удалять элементы;
    - в Iterator исправлены имена методов для повышения читаемости кода
    (Enumeration.hasMoreElements() соответствует Iterator.hasNext(), Enumeration.nextElement() соответствует Iterator.next() и т.д);
    - Enumeration присутствуют в устаревших классах, таких как Vector/Stack, тогда как Iterator есть во всех современных классах-коллекциях.
    7. Как между собой связаны Iterable, Iterator и «for-each»?
    Интерфейс Iterable имеет только один метод - iterator(), который возвращает объект-Iterator.
    Iterable
    Iteratoriterator() Возвращает объект-итератор.
    Класс Iterator отвечает за безопасный проход по списку элементов, имеет всего 3 метода: hasNext() — возвращает true или false в зависимости от того, есть ли в списке следующий элемент, или мы уже дошли до последнего. next() — возвращает следующий элемент списка remove() — удаляет элемент из списка
    Классы, реализующие интерфейс Iterable, могут применяться в конструкции for-each, которая использует Iterator.
    // Iterating over collection 'c' using Iterator for (Iterator i = c.iterator(); i.hasNext(); )
    System.out.println(i.next());
    8. Можно ли итерируясь по ArrayList удалить элемент? Какое вылетит исключение?
    Если не через iterator, например через for each - то будет исключение
    В Java для удаления элементов во время перебора нужно использовать специальный объект — итератор (класс Iterator) for (Cat cat: cats) { if (cat.name.equals("Бегемот")) { cats.remove(cat);
    }
    } java.util.
    ConcurrentModificationException
    Iterator catIterator = cats.iterator();//создаем итератор while(catIterator.hasNext()) {//до тех пор, пока в списке есть элементы
    Cat nextCat = catIterator.next();//получаем следующий элемент
    System.out.println(nextCat);//выводим его в консоль
    }
    9. Как поведёт себя коллекция, если вызвать iterator.remove()?
    Если вызову iterator.remove() предшествовал вызов iterator.next(), то iterator.remove() удалит элемент коллекции, на который указывает итератор, в противном случае будет выброшено
    IllegalStateException().
    Iterator it = names.iterator(); while (it.hasNext()) {
    String el = it.next(); if (el.equals("")) { for (String el: names) { if (el.equals("")) { names.remove(el); // WRONG!
    }
    it.remove(); // it’s norm
    }
    }
    10. Чем Set отличается от List?
    Set описывает неупорядоченную коллекцию, не содержащую повторяющихся элементов
    List представляет собой коллекцию, в которой допустимы дублирующие значения. Элементы такой коллекции пронумерованы, начиная от нуля, к ним можно обратиться по индексу.
    11. Расскажите про интерфейс Set.
    Представляет собой неупорядоченную коллекцию, которая не может содержать дублирующиеся данные. Является программной моделью математического понятия «множество».
    Set не добавляет новых методов, только вносит изменения в унаследованные.
    Множество, как и список, и любую коллекцию (и не только) можно обойти в цикле for-each: for (Integer number : intSet) {
    System.out.println(number);
    }
    Но вот доступ по индексу (порядковому номеру) (метод list.get(int index)) есть только у List, у Set этого метода нет. Это связано с тем, что порядок элементов во множестве не определён.
    Интерфейс
    Set
    включает следующие методы:
    Метод
    Описание
    add(Object o)
    Добавление элемента в коллекцию, если он отсутствует. Возвращает true, если элемент добавлен. addAll(Collection c)
    Добавление элементов коллекции, если они отсутствуют. clear()
    Очистка коллекции. contains(Object o)
    Проверка присутствия элемента в наборе. Возвращает true, если элемент найден. containsAll(Collection c)
    Проверка присутсвия коллекции в наборе. Возвращает true, если все элементы содержатся в наборе. equals(Object o)
    Проверка на равенство. hashCode()
    Получение hashCode набора. isEmpty()
    Проверка наличия элементов. Возвращает true если в коллекции нет ни одного элемента. iterator()
    Функция получения итератора коллекции. remove(Object o)
    Удаление элемента из набора. removeAll(Collection c)
    Удаление из набора всех элементов переданной коллекции. retainAll(Collection c)
    Удаление элементов, не принадлежащих переданной коллекции. size()
    Количество элементов коллекции toArray()
    Преобразование набора в массив элементов. toArray(T[] a)
    Преобразование набора в массив элементов. В отличии от предыдущего метода, который возвращает массив объектов типа
    Object, данный метод возвращает массив объектов типа, переданного в параметре.
      1   2   3   4   5


    написать администратору сайта