1、在集合中使用泛型前后的对比
1. 什么是泛型?
所谓泛型,就是允许在定义类、接口时通过一个`标识`表示类中某个`属性的类型`或者是某个方法的`返回值或参数的类型`。
这个类型参数将在使用时(例如,继承或实现这个接口、创建对象或调用方法时)确定(即传入实际的类型参数,也称为
类型实参)。
2. 在集合中使用泛型之前可能存在的问题
问题1:添加的数据类型不安全
问题2:繁琐:必须要使用向下转型。 还可能会报ClassCastException
@Test
public void test2(){
// List<Integer> list = new ArrayList<Integer>();
ArrayList<Integer> list = new ArrayList<>(); //jdk7.0新特性:类型推断
//添加学生的成绩
list.add(78);
list.add(87);
list.add(66);
list.add(99);
list.add(66);
//1.如下的操作,编译不通过
// list.add("AA");
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
//2.不需要使用向下转型
Integer score = iterator.next();
System.out.println(score);
}
}
@Test
public void test3(){
HashMap<String,Integer> map = new HashMap<>();
map.put("Tom",78);
map.put("Jerry",88);
map.put("Jack",55);
map.put("Rose",89);
// map.put(56,"Tony");//编译不通过
Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
Iterator<Map.Entry<String,Integer>> iterator = entrySet.iterator();
while(iterator.hasNext()){
Map.Entry<String,Integer> entry = iterator.next();
System.out.println(entry.getKey() + "--->" + entry.getValue());
}
}
2、在其它结构中使用泛型
public class Employee implements Comparable<Employee>{
private String name;
private int age;
private MyDate Birthday;
//省略get、set、构造器、toString()
@Override
public int compareTo(Employee o) {
// if (this == o){
// return 0;
// }
return this.name.compareTo((o.name));
}
}
//定制排序
@Test
public void test2() {
Employee e1 = new Employee("Tom", 23, new MyDate(1999, 12, 3));
Employee e2 = new Employee("Jerry", 33, new MyDate(1990, 2, 3));
Employee e3 = new Employee("Peter", 22, new MyDate(2000, 3, 5));
Employee e4 = new Employee("NiPing", 23, new MyDate(2000, 12, 5));
Employee e5 = new Employee("Fengyi", 20, new MyDate(2002, 9, 9));
Comparator<Employee> comparator = new Comparator<>() {
@Override
public int compare(Employee e1, Employee e2) {
if (e1 == e2) {
return 0;
}
int yearDistance = e1.getBirthday().getYear() - e2.getBirthday().getYear();
if (yearDistance != 0) {
return yearDistance;
}
int monthDistance = e1.getBirthday().getMonth() - e2.getBirthday().getMonth();
if (monthDistance != 0) {
return monthDistance;
}
return e1.getBirthday().getDay() - e2.getBirthday().getDay();
}
};
TreeSet<Employee> treeSet = new TreeSet<>(comparator);
treeSet.add(e1);
treeSet.add(e2);
treeSet.add(e3);
treeSet.add(e4);
treeSet.add(e5);
Iterator<Employee> iterator = treeSet.iterator();
while (iterator.hasNext()) {
Employee e = iterator.next();
System.out.println(e);
}
}
3、如何自定义泛型类、泛型接口、泛型方法
1. 自定义泛型类\接口
1.1 格式
class A<T>{}
interface B<T>{}
1.2 使用说明
> 声明的泛型类,在实例化时可以不使用类的泛型。
> 声明泛型类以后,可以在类的内部结构中,使用类的泛型参数。比如:属性、方法、构造器
> 何时指明具体的类的泛型参数类型呢?① 类的实例化 ② 提供子类时
> 泛型参数类型只能是引用数据类型,不能使用基本数据类型。
> 一旦指定类的泛型参数的具体类型以后,则凡是使用类的泛型参数的位置,都确定为具体的泛型参数的类型。
如果实例化时未指定泛型参数的具体类型,则默认看做是Object类型。
> 泛型类中,使用泛型参数的属性、方法是不能声明为static的。
2. 自定义泛型方法
2.1 问题:在泛型类的方法中,使用了类的泛型参数。那么此方法是泛型方法吗?
2.2 格式
权限修饰符 <T> 返回值类型 方法名(形参列表){}
2.3 举例
public <E> ArrayList<E> copyFromArrayToList(E[] arr){
2.4 说明
> 泛型方法所在的类是否是一个泛型类,都可以。
> 泛型方法中的泛型参数通常是在调用此方法时,指明其具体的类型。
一旦指明了其泛型的类型,则方法内部凡是使用方法泛型参数的位置都指定为具体的泛型类型。
> 泛型方法可以根据需要声明为static
4、泛型在继承上的体现
1. 类A是类B的父类,则G<A> 与 G<B>的关系:没有继承上的关系。
比如:ArrayList<String>的实例就不能赋值给ArrayList<Object>
2. 类A是类B的父类或接口,A<G> 与 B<G>的关系:仍然满足继承或实现关系。意味着可以使用多态。
比如:将ArrayList<String>的类型的变量赋值给List<String>的变量,是可以的。
5、通配符、有条件限制的通配符的使用
1. 通配符: ?
2. 使用说明:
2.1 举例:
List<?> list1 = null;
List<Object> list2 = new ArrayList<Object>();
List<String> list3 = null;
list1 = list2;
list1 = list3;
2.2 说明:可以将List<?>看做是List<Object> 、 List<String>结构共同的父类
3. 读写数据的特点
> 读取:可以读数据,但是读取的数据的类型是Object类型。
> 写入:不能向集合中添加数据。特例:null
4. 有限制条件的通配符
List<? extends A> : 可以将List<A> 或 List<SubA>赋值给List<? extends A>。其中SubA是A类的子类
List <? super A> : 可以将List<A> 或 List<SuperA>赋值给List<? super A>。其中SuperA是A类的父类
5. 有限制条件的统配符的读写操作(难、了解)
见代码