文章目录
一、为什么要有泛型
泛型的设计背景
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的。
例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型
。Collection<E>, List<E>, ArrayList<E>
这个<E>
就是类型参数,即泛型。
二、在集合中使用泛型
- ① 集合接口或集合类在jdk5.时都修改为带泛型的结构。
- ② 在实例化集合类时,可以指明具体的泛型类型
- ③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构使用到类的泛型的位置,都指定为实例化的泛型类型。比如: add(E e) —> 实例化以后: add(Integer e)
- ④ 注意点:
泛型的类型必须是类
,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
- ⑤ 如果实例化时,没有指明泛型的类型。
默认类型为java.lang.object类型
。
三、自定义泛型结构
3.1 泛型类和泛型接口
例子
public class Order<T> {
String orderName;
int orderId;
//类的内部结构就可以使用类的泛型
T orderT;
public Order(String orderName, int orderId, T orderT) {
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
}
总结
- 1.泛型类可能有多个参数,此时应将多个参数一.起放在尖括号内。比如:.
<E1,E2, E3> - 2.泛型类的构造器如下:
public GenericClass(){}
。而下面是错误的:public GenericClass<E>(){}
- 3.实例化后,操作原来泛型位置的结构必须与指定的泛型类型–致。|
- 4.泛型不同的引用不能相互赋值。
尽管在编译时
ArrayList<String>
和ArrayList<Integer>
是两种类型,但是,在运>行时只有一个ArrayList被加载到JVM中
。
- 5.泛型如果不指定,将被擦除,
泛型对应的类型均按照Object处理,但不等价于Object
。 - 6.如果泛型类是一个接口或抽象类,则不可创建泛型类的对象。
- 7 jdk1.7泛型的简化操作:
ArrayList<Fruit> flist = new ArrayList<>();
- 8.泛型的指定中
不能使用基本数据类型
,可以使用包装类替换
。
3.2 泛型方法
泛型方法:
在方法中出现了泛型的结构,泛型参数与类的泛型参数没有任何关系。换句话说,泛型方法所属的类是不是泛型类都没有关系
。
泛型方法,可以声明为静态的
。原因: 泛型参数是在调用方法时确定的。并非在实例化类时确定。
例子
public <E> List<E> copyFromArrayTolist(E[] arr) {
ArrayList<E> list = new ArrayList<>();
for (E e : arr) {
list.add(e);
}
return list;
}
四、泛型在继承上的体现
class Father<T1, T2> {}
//子类不保留父类的泛型
// 1)没有类型擦除
class Son<A, B> extends Father {
//等价于class Son extends Father<0bject , object>{}
}
// 2)具体类型
class Son2<A, B> extends Father<Integer, String> {}
//子类保留父类的泛型
// 1)全部保留
class Son3<T1, T2, A, B> extends Father<T1, T2> {}
// 2)部分保留
class Son4<T2, A, B> extends Father<Integer, T2> {}
五、通配符的使用——通配符: ?
5.1 使用类型通配符: ?
-
比如: List<?> ,Map<?,?>
List<?>是List<String>
、List<Object>
等各种泛型List的父类。 -
读取
List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,它包含的都是Object。 -
写入
list中的元素时,不行。因为我们不知道c的元素类型,我们不能向其中添加对象。➢唯一的例外是null,它是所有类型的成员。
例子:? 通配符相当于Object和String的通用父类,此时可以实现赋值
- 类A是类B的父类,
G<A>
和G<B>
是没有关系的,二者共同的父类是:G<?>
- 将任意元素加入到其中
不是类型安全
的:
Collection<?> C = new ArrayList();
c.add(new Object()); //编译时错误。因为我们不知道c的元素类型,我们不能向其中添加对象。
public void test3() {
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null;
list = list1;
list = list2;
print(list1);
print(list2);
}
public void print(List<?> list) {
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()) {
Object obj = iterator.next();
System.out.println(obj);
}
}
5.2 有限制条件的通配符
<?> 允许所有泛型的引用调用
5.2.1 通配符指定上限
上限extends
——使用时指定的类型必须是继承某个类,或者实现某个接口,即<=
5.2.2 通配符指定下限
下限super
——使用时指定的类型不能小于操作的类,即 >=
举例:
- ➢
<? extends Number> (无穷小,Number]
只允许泛型为Number及Number子类的引用调用 - ➢
<? super Number> [Number,无穷大)
只允许泛型为Number及Number父类的引用调用 - ➢
<? extends Comparable>
只允许泛型为实现Comparable接口的实现类的引用调用
六 其他
6.1 DAO
DAO:data(base) access object