1 of 18

Контейнеры и генерики �в Java

2 of 18

Работа с “похожими объектами”

  • массивы
    • фиксированное количество
    • быстрое время доступа
  • контейнерные типы данных
    • списки
    • стеки
    • деревья
    • хеш-таблицы
    • ...

3 of 18

Обобщённые контейнеры

  • хранить внутри контейнеров Object’ы
    • Object pop();
    • int value = (Integer) stack.pop());
  • в контейнер можно положить что угодно
    • даже разных типов

4 of 18

Generic containers

  • public class SimpleCollection {
  • public static void main(String[] args) {
  • Collection<Integer> c = new ArrayList<>();
  • for (int i = 0; i < 10; i++)
  • c.add(i); // Autoboxing
  • for (Integer i : c)
  • System.out.print(i + ", ");
  • }
  • }
  • /* Output:
  • 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
  • */

5 of 18

java.util.Collection

  • boolean add​(E e)
  • boolean addAll​(Collection<? extends E> c)
  • void clear​()
  • boolean contains​(Object o)
  • boolean isEmpty​()
  • Iterator<E> iterator​()
  • boolean remove​(Object o)
  • int size​()
  • Object[] toArray​()
  • <T> T[] toArray​(T[] a)

6 of 18

Итераторы

  • средство унифицированной работы с коллекциями
    • создание посредством Collection::iterator()
    • next()
    • hasNext()
    • remove()

7 of 18

Использование итератора

  • public static void main(String[] args) {
  • List<String> states = new ArrayList<>();
  • states.add("Германия"); states.add("Франция");
  • states.add("Италия"); states.add("Испания");
  • Iterator<String> it = states.iterator();
  • while (it.hasNext()) {
  • System.out.println(it.next());
  • }
  • for (String s : states) {
  • System.out.println(s);
  • }
  • }

8 of 18

9 of 18

  • public class TwoTuple<A, B> {
  • public final A first;
  • public final B second;
  • public TwoTuple(A a, B b) { first = a; second = b; }
  • public String toString() {
  • return "(" + first + ", " + second + ")";
  • }
  • }
  • public class ThreeTuple<A, B, C> extends TwoTuple<A, B> {
  • public final C third;
  • public ThreeTuple(A a, B b, C c) {
  • super(a, b);
  • third = c;
  • }
  • public String toString() {
  • return "(" + first + ", " + second + ", " + third +")";
  • }
  • }

10 of 18

Generic-методы

  • public class GenericMethods {
  • public <T> void f(T x) {
  • System.out.println(x.getClass().getName());
  • }
  • public static void main(String[] args) {
  • GenericMethods gm = new GenericMethods();
  • gm.f("");
  • gm.f(1);
  • gm.f(1.0);
  • gm.f(1.0F);
  • gm.f(‘c’);
  • gm.f(gm);
  • }
  • }

/* Output:

java.lang.String

java.lang.Integer

java.lang.Double

java.lang.Float

java.lang.Character

GenericMethods */

11 of 18

Вызов static generic-методов

  • public class New {
  • public static <K, V> Map<K, V> map() {
  • return new HashMap<K, V>();
  • }
  • public class ExplicitTypeSpecification {
  • static void f(Map<Type1, List<Type2>> arg) {}
  • public static void main(String[] args) {
  • f(New.<Type1, List<Type2>>map());
  • }
  • }

12 of 18

Стирание типов

  • внутри генерика его тип неизвестен
  • в рантайме List<String> и List<Integer> -- одно и то же

Class c1 = new List<Integer>().getClass();

Class c2 = new List<String>().getClass();

System.out.print(c1 == c2); // возвращает true!

13 of 18

Пример из С++

template<class T> class Manipulator {

T obj;

public:

Manipulator(T x) { obj = x; }

void manipulate() { obj.f(); }

};

class HasF {

public:

void f() {

cout << "HasF::f()" << endl;

}

};

int main() {

HasF hf;

Manipulator<HasF> man(hf);

man.manipulate();

}

/* Output:

HasF::f()*/

14 of 18

Аналогичный код в Java

class Manipulator2<T extends HasF> {

private T obj;

public Manipulator2(T x) { obj = x; }

public void manipulate() { obj.f(); }

}

15 of 18

public class ArrayMaker<T> {

private Class<T> kind;

public ArrayMaker(Class<T> kind) { this.kind = kind; }

@SuppressWarnings("unchecked")

T[] create(int size) {

return (T[])Array.newInstance(kind, size);

}

public static void main(String[] args) {

ArrayMaker<String> stringMaker =

new ArrayMaker<String>(String.class);

String[] stringArray = stringMaker.create(9);

System.out.println(Arrays.toString(stringArray));

}

}

/* Output: [null, null, null, null, null, null, null, null, null]*/

16 of 18

public class FilledListMaker<T> {

List<T> create(T t, int n) {

List<T> result = new ArrayList<T>();

for(int i = 0; i < n; i++)

result.add(t);

return result;

}

public static void main(String[] args) {

FilledListMaker<String> stringMaker =

new FilledListMaker<String>();

List<String> list = stringMaker.create("Hello", 4);

System.out.println(list);

}

}

/* Output: [Hello, Hello, Hello, Hello] */

17 of 18

public class SimpleHolder {

private Object obj;

public void set(Object obj) { this.obj = obj; }

public Object get() { return obj; }

public static void main(String[] args) {

SimpleHolder holder = new SimpleHolder();

holder.set("Item");

String s = (String)holder.get();

}

}

public class GenericHolder<T> {

private T obj;

public void set(T obj) { this.obj = obj; }

public T get() { return obj; }

public static void main(String[] args) {

GenericHolder<String> holder = new GenericHolder<String>();

holder.set("Item");

String s = holder.get();

}

}

18 of 18

Как делать нельзя

public class Erased<T> {

private final int SIZE = 100;

public static void f(Object arg) {

if(arg instanceof T) {} // Error

T var = new T(); // Error

T[] array = new T[SIZE]; // Error

T[] array = (T[])new Object[SIZE]; // Unchecked warning

}

}