泛型
泛型是jdk1.5使用的新特性。
泛型的好处:
1. 将运行时的异常提前至了编译时。
2. 避免了无谓的强制类型转换 。
泛型在集合中的常见应用:
ArrayList<String> list = new ArrayList<String>(); true 推荐使用。
ArrayList<Object> list = new ArrayList<String>(); false
ArrayList<String> list = new ArrayList<Object>(); false
//以下两种写法主要是为了兼顾新老系统的兼用性问题。
ArrayList<String> list = new ArrayList(); true
ArrayList list = new ArrayList<String>(); true
注意:泛型没有多态的概念,左右两边的数据类型必须要一致,或者只是写一边的泛型类型。
推荐使用:两边都写泛型。
出现问题:存入的是特定的对象,取出的时候是Object对象,需要强制类型转换,可能诱发类型转换异常.无法控制存入的是什么类型的对象,取出对象的时候进行强转时可能诱发异常.而且在编译时期无法发现问题.
虽然可以再类型转换的时候通过if语句进行类型检查(instanceof),但是效率较低.可以通过给容器加限定的形式规定容器只能存储一种类型的对象.就像给容器贴标签说明该容器中只能存储什么样类型的对象。
泛型应用:
格式:集合类<类类型> 变量名 = new 集合类<类类型>();
1. 将运行时的异常提前至编译时发生。
2. 获取元素的时候无需强转类型,就避免了类型转换的异常问题
格式 通过<> 来指定容器中元素的类型.
什么时候使用泛型:当类中操作的引用数据类型不确定的时候,就可以使用泛型类.
泛型类型必须是引用类型,在泛型中不能使用基本数据类型,如果需要使用基本数据类型,那么就使用基本数据类型对应的包装类型。
八种基本数据类型对应的引用类型:
byte----> Byte short---> Short int----> Integer long----> Long
double ----> Double float -----> Float
boolean---->Boolean
char----> Character
泛型:就是将类型当作变量处理。规范泛型的定义一般是一个大写的任意字母。
自定义泛型:自定义泛型就是一个数据类型的占位符或者是一个数据类型的变量。
方法上自定义泛型:
修饰符 <声明自定义的泛型>返回值类型 函数名(使用自定义泛型 ...){
}
方法泛型注意的事项:
1. 在方法上自定义泛型,这个自定义泛型的具体数据类型是在调用该方法的时候传入实参时确定具体的数据类型的。
2. 自定义泛型只要符合标识符 的命名规则即可, 但是自定义泛型我们一般都习惯使用一个大写字母表示。 T Type E Element
public static void main(String[] args) {
String str = getDataType("abcdef");
Integer i = getDataType(1232345);
}
public <T> T getDataType(T data) {
return data;
}
细节:使用泛型方法前需要进行泛型声明,使用一对尖括号 <泛型>,声明的位置在static后返回值类型前。当一个类中有多个函数声明了泛型,那么该泛型的声明可以声明在类上。
泛型类
泛型类的定义格式:
class 类名<声明自定义泛型>{
}
泛型类要注意的事项:
1. 在类上,自定义泛型的具体数据类型是在使用该类创建对象的时候确定的。
2. 如果一个类在类上已经声明了自定义泛型,如果使用该类创建对象的时候没有指定 泛型的具体数据类型,那么默认为Object类型
3.在类上自定义泛型不能作用于静态的方法,如果静态的方法需要使用自定义泛型,那么需要在方法上自己声明使用。
注意:静态方法不可以使用类中定义的泛型。因为类中的泛型需要在对象初始化时指定具体的类型,而静态优先于对象存在。那么类中的静态方法就需要单独进行泛型声明,声明泛型一定要写在static后,返回值类型之前
泛型类细节:
1、创建对象的时候要指定泛型的具体类型
2、创建对象时可以不指定泛型的具体类型(和创建集合对象一眼)。默认是Object,例如我们使用集合存储元素的时候没有使用泛型就是那么参数的类型就是Object。
3、类上面声明的泛型只能应用于非静态成员函数,如果静态函数需要使用泛型,那么需要在函数上独立声明。
4、如果建立对象后指定了泛型的具体类型,那么该对象操作方法时,这些方法只能操作一种数据类型。
5、所以既可以在类上的泛型声明,也可以在同时在该类的方法中声明泛型。
泛型接口
泛型接口的定义格式:
interface 接口名<声明自定义泛型>{
}
泛型接口要注意的事项:
1. 接口上自定义的泛型的具体数据类型是在实现一个接口的时候指定 的。
2. 在接口上自定义的泛型如果在实现接口的时候没有指定具体的数据类型,那么默认为Object类型。
目前实现一个接口时,还不明确目前要操作的数据类型,要等待创建接口实现类对象的时候,才能指定泛型的具体数据类型。
如果要延长接口自定义泛型的具体数据类型,那么格式如下:
格式:
public class Demo4<T> implements Dao<T>{
}
泛型通配符
泛型的上下限:
需求1: 定义一个函数可以接收接收任意类型的集合对象,要求接收的集合对象只能存储Integer或者是Integer的父类类型数据。
需求2: 定义一个函数可以接收接收任意类型的集合对象,要求接收的集合对象只能存储Number或者是Number的子类类型数据。
泛型中通配符: ?
? super Integer : 只能存储Integer或者是Integer父类元素。 泛型的下限
? extends Number : 只能存储Number或者是Number类型的子类数据。 泛型上限。
正确:Vector<? extends Number> x = new Vector<Integer>();
错误:Vector<? extends Number> x = new Vector<String>();
正确:Vector<? super Integer> x = new Vector<Number>();
错误:Vector<? super Integer> x = new Vector<Byte>();
注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。