Java. Generics. Wildcards
1. Зачем нужны дженерики
Дженерики появились в Java в версии 1.5, для того, чтобы исключить неверную типизацию.
Пример, до Java 1.5, были raw types (сырые типы) . В данном примере objects - это raw type:
List objects = new ArrayList();
objects.add("1");
objects.add("2");
objects.add("3");
objects.add("4");
objects.add("5");
String s0 = (String) objects.get(0);
String s1 = (String) objects.get(1);
String s2 = (String) objects.get(2);
String s3 = (String) objects.get(3);
String s4 = (String) objects.get(4);
Тут все работает верно и ошибок нет, т.к. мы в массив List
добавляем String.
Но что будет если мы ошибемся и добавим не строку "4", а число 4:
List objects = new ArrayList();
objects.add("1");
objects.add("2");
objects.add("3");
objects.add(4); //тут наша ошибка
objects.add("5");
String s0 = (String) objects.get(0);
String s1 = (String) objects.get(1);
String s2 = (String) objects.get(2);
String s3 = (String) objects.get(3);
String s4 = (String) objects.get(4);Мы получим в рантайме ошибку:Exception in thread "main" java.lang.ClassCastException:
java.lang.Integer cannot be cast to java.lang.String
Конечно, нам хотелось бы, чтобы данная ошибка была на этапе компиляции, а не в рантайме.
Поэтому нам нужно использовать Дженерики:
List<String> objects = new ArrayList();
Благодаря дженерикам:а)мы избавились от ошибки ClassCastException:
objects.add(4);
б) Убрали приведение типов (String) и код стал выглядеть проще:Наш код будет выглядеть так:List<String> objects = new ArrayList();
objects.add("1");
objects.add("2");
objects.add("3");
objects.add("4");
objects.add("5");
String s0 = objects.get(0);
String s1 = objects.get(1);
String s2 = objects.get(2);
String s3 = objects.get(3);
String s4 = objects.get(4);2.Основная проблема с коллекциями. Знакомство с wildcard
Класс Parent:public class Parent {
private String name;
public Parent(String name) {
this.name = name;
}
public String getName() {
return name;
}
}Ну и наследник Child:public class Child extends Parent {
public Child(String name) {
super(name);
}
}Сделаем какой-нибудь простенький метод для печати:static void print(List<Parent> par) {
for (Parent p : par) {
System.out.println(p.getName());
}
}И попробуем распечатать коллекцию ParentsList<Parent> parents = new ArrayList<>();
parents.add(new Parent("parent 1"));
parents.add(new Parent("parent 2"));
parents.add(new Parent("parent 3"));
print(parents);То ошибок тут не будет :name 1 name 2 name 3Но !!! Если мы попробуем распечатать список детей, то получим ошибку:List<Child> children = new ArrayList<>();
children.add(new Child("child 1"));
children.add(new Child("child 2"));
children.add(new Child("child 3"));
print(children);Что List<Child> НЕ наследуется от List<Parent>. Те Класс Childнаследуется от Класса Parent, но List<Child>НЕ наследуется от List<Parent>.List<Child> наследуется от Collection<Child>, а Collection<Child>наследуется от Iterable<Child>, а потом идет класс Object.Соответственно, у List<Child> и List<Parent> общий родитель Object.Соответственно используется wildcard или по-другому Joker - ?.static void print(List<? extends Parent> par) {
for (Parent p : par) {
System.out.println(p.getName());
}
}List<? extends Parent> - данная запись означает, что в List можнопередавать любых потомков класса Parent и сам класс Parent.
Комментарии
Отправить комментарий