Java – 泛型
简介
泛型是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
泛型的格式: <数据类型>
注意:泛型只能支持引用数据类型
泛型的细节
1.统一数据类型
2.把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
3.泛型中不能写基本数据类型
4.指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型
5.如果不写泛型,类型默认是Object
泛型类
当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类
修饰符 class 类名<类型>{}
public class ArrayList<E>{}
此处E可以理解为变量,但是不是用来记录数据的,而是记录类据类型的,可以为任意名。
举例:定义一个泛型类
// 增加方法,使用泛型定义,这样当传入什么类型的数据时,它就是什么类型的
public boolean add(E e){
elementObjects[size] = e;
return true;
}
// 取出数据时,也会返回这个类型的数据
public E get(int index){
// 因为存储数据时使用的是 Object[] 保存的,所以取出时也是 Object[] 的
// 因此需要在传出时做一个类型强转,强转为泛型数据
return (E) elementObjects[index];
}
泛型方法
当我们只在类方法中需要使用泛型类型的时候,我们可以把类作为一个泛型类,泛型类可以在类的所有地方都使用泛型,但当我们只想在某个方法中使用泛型时,我们可以只在方法中单独定义泛型,我们只在方法中定义的泛型叫泛型方法。
修饰符 <E> 返回值 方法名(){}
public static <E> int get(){}
public static <E> boolean set(E e){}
注意,泛型 <E> 要在 修饰符后面,public 和 static 都是修饰符。
举例:定义一个泛型方法
// 增加方法,使用泛型定义,这样当传入什么类型的数据时,它就是什么类型的
public <E> boolean add(E e){
elementObjects[size] = e;
return true;
}
// 取出数据时,也会返回这个类型的数据
public <E> E get(int index){
// 因为存储数据时使用的是 Object[] 保存的,所以取出时也是 Object[] 的
// 因此需要在传出时做一个类型强转,强转为泛型数据
return (E) elementObjects[index];
}
泛型接口
当这个接口的类型是不明确的,可以定义泛型接口
修饰符 interface 接口名<类型> {}
public interface List<E>{}
泛型接口应用-实现类明确
当接口定义了泛型时,实现类可以明确的实现类型方法,可以在实现接口时明确传递接口类型
实现类明确表示会实现类型为 String 的接口方法
通过定义明确的类型方法后,所有重写接口方法上用到的泛型都变成明确类型
public class ArrayList implements Line<String> {
public void add(String e)
}
泛型接口应用-实现类不明确
如果实现类中,依然对泛型接口中的类型不明确时,实现类可以继承接口中的泛型,这样在接口中需要使用到泛型类型中的方法,依然会采用泛型定义
如果实现类的类型依然不确定,可以在实现类中继续定义泛型就可以
后面的重写方法依然会使用泛型类进行计算
public class ArrayList<E> implements Line<E> {
public void add(E e)
}
泛型继承性
对于泛型来说,泛型是不具备继承性的,但数据具备继承性,比如
定义三个类,Zi 类 继承 Fu 类,Fu 类 继承 Ye 类
class Ye {}
class Fu extends Ye {}
class Zi1 extends Fu {}
定义一个需要传入指定泛型的方法
public static void method(ArrayList<Ye> list){ }
定义两个对象,一个实例 Ye类,一个实例 Fu类
ArrayList<Ye> ye = new ArrayList<>();
ArrayList<Fu> fu = new ArrayList<>();
此时调用method传入 Ye 类 的对象是被允许的
method(ye);
但是调用method传入 fu 类 的对象是不被允许的
method(fu);
method 中定义了传入的泛型类要求是 <Ye> 时,就只允许传入 <Ye> 的对象,即使是它的子类 Fu 类也是不被允许的。
但是当传入子类时可以具备继承性,比如下面
创建一个存储 Ye 类 的集合
ArrayList<Ye> ye = new ArrayList<>();
// 创建两个 Ye类 的子类 Fu 和 Zi
Fu f = new Fu();
Zi z = new Zi();
// 此时,Ye 类集合允许传入其子类的数据
ye.add(f);
ye.add(z);
总结:如果需要传入子类型的泛型类到带有 父类型的泛型类,是不被允许的,但如果把 子类 传递 父类 是被允许的(和多态一样)
泛型通配符
泛型可以传递任意类型,那当一些无关类也能被传入。
那我要如何限制,只允许某些类型能传入呢?
<?> 不限制类型
<?> 通配符和 <E> 是同样的功能, <E> 指的是任意类型,而 <?> 指的是通配类型,带有通配符功能,但是不写任部通配条件时,则和 <E> 是一样的
public <E> void method(ArrayList<E> e){}
等同于
public void method2(ArrayList<?> e){}
<? extends E> 限制继承子类
<? extends E> 表示可以传递 E类型 或者 E 所有的子类类型
public static void method(ArrayList<? extends Ye> e){ }
表示如果要调用 method 方法时,可以传入 Ye 类型的和所有其子类,即 Fu类和Zi 类都可以被传入,非 Ye 类子类的就不允许传入
当类是泛型类时,定义了泛型 E,此时方法中定义了 <? extends E> 表示,方法中只允许传入类型的子类或传入类本身的对象
public static void method(ArrayList<? extends E> e){ }
XXX<Fu> x = new XXX<>();
s.method(Fu类和Zi类)
s.method(不允许Ye类)
<? super E> 限制父类
<? super E> 表示可以传递 E类型 或者 E 所有的父类类型
public static void method(ArrayList<? super Fu> e){ }
表示如果要调用 method 方法时,可以传入 Fu类型的所有父类,即 Ye 类 ,非Fu 类的父类不允许传入,如Zi类是Fu类的子类,就不允许被传入
当类是泛型类时,定义了泛型 E,此时方法中定义了 <? super E> 表示,方法中只允许传入类型的父类或传入类本身的对象
public static void method(ArrayList<? super E> e){ }
XXX<Fu> x = new XXX<>();
s.method(Fu类和Ye类)
s.method(不允许Zi类)
应用场景
1.如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口
2.如果类型不确定,但是能知道以后只能传递某个继承体系中的类,就可以泛型的通配符。
共有 0 条评论