泛型:类型的参数化。就是定义类、接口时,可以将要使用到的某个数据类型定义成一个参数,在真正使用类或接口时再去确定

  • 如果泛型类使用么有指定的类型,那么泛型将为Object类型
  • 实现泛型接口,并且确定泛型的类型,这样这个类就不是泛型类
  • 定义一个子类继承泛型接口或者泛型类时,泛型的类型依旧不能确定,那么就得在子类上再次定义泛型,表示在使用子类时去明确泛型的类型,这样子类就是泛型类
  • 泛型类、接口,泛型的个数可以有多个,用逗号隔开
  • 泛型方法
  • 注意:不能创建泛型数组,T[] t = new T[5]; 编译不通过

泛型类

泛型类,尖括号中是一个类型的参数,在使用类时再明确具体的类型

泛型类中可以使用这个类型的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Data<T> {
String name;
int age;
// 给属性声明为T类型
T x;
public Data(String name,int age,T x) {
this.name = name;
this.age = age;
this.x = x;
}
// 不是泛型方法
public void setX(T x) {
this.x = x;
}
// 不是泛型方法
public T getX() {
return x;
}
// 泛型方法中的泛型跟当前类没有任何关系
// 泛型参数E不跟类有任何关系
public <E> E func(E e) {
return e;
}
}

泛型接口

1
2
3
4
5
6
7
/*
* 泛型接口,泛型的个数可以有多个,用逗号隔开
*/
public interface MyInterface<T,V>{

public void func(T t,V v);
}
1
2
3
4
5
6
7
8
9
/*
* 实现泛型接口,并且确定泛型的类型,这样这个类就不是泛型类
*/
public class SubClass implements MyInterface<String, Integer> {

@Override
public void func(String t, Integer v) {
}
}

泛型方法

1
2
3
4
5
6
7
8
9
10
11
Data<Integer> d1 = new Data<Integer>("abc", 20, 10);
d1.setX(500);

// 泛型方法的使用
// 传入的参数是什么类型,那么方法中的泛型即为这个类型
Integer res = d1.func(100);
String res2 = d1.func("abc");

// 如果泛型类使用么有指定的类型,那么泛型将为Object类型
Data d2 = new Data("aaa", 20, 2);
d2.setX("object");

通配符

有的时候想定义一个方法,里面的参数是一个集合对象,但是集合的泛型又不太确定

?:代表泛型的通配符,参数链表中的泛型将可以为任意的

通配符范围的限定:

  • ? extends X:泛型必须是X本身或者其子类
  • ? super X:泛型必须是本身或者X的父类
1
2
3
4
5
6
7
8
9
10
11
private void f1(List<?> list) {
// 当前这种情况只能添加null
// list.add("abc");
// list.add(100);
// list.add(new Object());
// list.add(null);

// 获取数据是可以的
Object data = list.get(0);
System.out.println(data);
}