当将一个对象放入集合中,集合不会记住此对象的类型,同时也不会进行添加数据的类型检查
List list=new ArrayList();
list.add(999);
list.add("zhangsan");
list.add(new Date());
for(Object tmp:list){
//需要获取集合中的日期类型数据,并获取对应日期的年号
if(tmp!=null && tmp instanceof Date){
Date dd=(Date)tmp; //如果 tmp 不是 Date 类型,进行类型窄化则异常
System.out.println(dd.getYear()+1900);
}
}
因此取出集合元素时需要人为的强制类型转化到具体的目标类型,但是很容易出现 ClassCastException 异常
那么有没有什么办法可以使集合能够记住集合内元素各类型,且能够达到只要编译时不出现问题,运行时就不 会出现 java.lang.ClassCastException
异常呢?
答案:就是使用泛型,可以将运行时的类型检查搬到编译期实现
什么是泛型
泛型是
jdk5 引入的类型机制,就是将类型参数化
定义方法:引入参数传递
---
形参和
实参
public int aaa(Double dd){ //定义时并不知道 dd 这个位置上的值是多少
if(dd==null) return 0;
return dd.intValue();
}
如果在定义类或者方法时,如果参数类型不能确定则可以使用泛型充当占位符
public int aaa(T obj){}
这里的
T
就可以理解为类型的形参,当然在调用的时候进行指定
- 泛型机制将类型转换时的类型检查从运行时提前到了编译时,使用泛型编写的代码比杂乱的使用 object 并 在需要时再强制类型转换的机制具有更好的可读性和安全性。
- 泛型在本质上是指类型参数化。所谓类型参数化,是指用来声明数据的类型本身,也是可以改变的,它由 实际参数来决定。在一般情况下,实际参数决定了形式参数的值。而类型参数化,则是实际参数的类型决定了 形式参数的类型。
在声明阶段
E
是什么类型不确定,这里的
E
仅仅充当占位符的作用,在具体调用时类型才能确定,而
E
的所 有位置将被指定的类型所替代
java 中泛型标记符
- E - Element (在集合中使用,因为集合中存放的是元素)
- T - Type(Java 类)
- K - Key(键)
- V - Value(值)
- N - Number(数值类型)
- ? - 表示不确定的 java 类型
Java的泛型是指在类或接口中使用一个或多个类型参数来定义类或接口中的成员变量、方法参数和返回值的类型,并在实例化对象时确定类型的机制。
泛型的优点:
- 提供编译时类型检查,可以在编译期捕获错误,减少运行时异常。
- 提高代码的可读性和可维护性,可以明确指定类型,并减少类型转换的需要。
- 提供了更好的代码复用性,可以创建通用的类或方法,适应不同类型的参数。
泛型的使用方式:
1. 类型参数:
在类或接口的定义中使用< >括起来的类型参数,可以有多个类型参数,通常用大写字母表示,如T、E、K、V等。
public class GenericClass<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
2. 泛型方法:
在方法的返回值前使用< >括起来的类型参数,可以与类的类型参数不同,也可以没有类型参数。
public class GenericMethod {
public <T> void printData(T data) {
System.out.println(data);
}
public <T, U> U convertData(T data) {
//...
}
}
3. 通配符:
用?表示,表示任意类型,可以用在泛型的上界、下界和无界通配符中。通配符一般用于读取数据时的灵活性,不能用于写入数据。
public void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
泛型的限制:
1. 不能使用基本数据类型作为类型参数,只能使用其对应的包装类。
2. 不能创建具有泛型类型参数的数组,但可以创建泛型类型的数组。
// 错误示例:
List<int> list = new ArrayList<>();
// 正确示例:
List<Integer> list = new ArrayList<>();
3. 泛型的类型参数在编译时会被擦除,泛型类的所有实例都共享同一份字节码,泛型参数的具体类型信息在运行时是不可知的。
总结:
Java的泛型是一种提供类型安全和代码复用的机制,可以在类、接口和方法中使用类型参数,在编译期进行类型检查,并提供了通配符来灵活处理不同类型的参数。但是泛型的类型参数在运行时是不可知的,需要注意泛型的限制和特点。