十一、泛型
1、概述
Java泛型(generics)是JDK 5中引入的一个新特性,泛型提供了编译时类型安全监测机制,该机制允许程序员在编译时监测非法的类型。使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。泛型对于集合类尤其有用,例如,ArrayList就是一个无处不在的集合类。
泛型的本质是参数化类型,也就是所操作的数据类型被指定为一个参数。把类型明确的工作推迟到创建对象或调用方法的时候才去明确具体的类型。<>内的类型只能是引用类型,当然对于基本类型,可以使用对应的包装类型。
2、泛型类
/**
* Java中的泛型类
*/
public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, Cloneable, Serializable {
...
}
public class ConcurrentHashMap<K,V> extends AbstractMap<K,V>
...
}
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
...
}
/**
* 定义泛型
*/
@Data
public class GenericityKV<K, V> {
private K key;
private V value;
public GenericityKV(K key, V value){
this.key = key;
this.value = value;
}
}
public static void main(String[] args) {
//定义需要指定具体类型Integer和String
GenericityKV<Integer, String> genericityKV = new GenericityKV<>(1,"字符串");
System.out.println("输出key 和 value:" + genericityKV.getKey() + genericityKV.getValue());
}
注意:
(1)、在实例化泛型类时,必须指定T的具体类型,类型只能是引用类型,当然对于基本类型,可以使用对应的包装类型。
(2)、不能对确切的泛型类型使用instanceof操作。如下面的操作是非法的,编译时会出错。 if(ex_string instanceof Genericity<Number>){ }
3、泛型接口
实现泛型接口:
(1)、不明确类型:
未传入泛型实参时,和泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中。如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class”。
(2)、明确类型
在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型。
/**
* Java中的泛型接口
*/
public interface Map<K,V> {
...
}
public interface List<E> extends Collection<E> {
...
}
/**
* 定义泛型
*/
public interface GenericityInterface<T> {
public T show();
}
/**
* 不明确类型
* 未传入泛型实参时,和泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
* 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
*/
public class GenericityInterfaceImpl<T> implements GenericityInterface<T> {
@Override
public T show(){
return null;
}
}
/**
* 明确类型
* 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
*/
public class GenericityInterfaceImpl implements GenericityInterface<String> {
@Override
public String show(){
return null;
}
}
4、泛型方法
泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型。
在普通类中定义的,而不是在泛型类中定义的,泛型必须得先定义才能够使用。然而,这是一个泛型方法,可以从尖括号和类型变量看出这一点。注意,类型变量(<>)放在修饰符public或public static的后面,返回类型的前面。
public <T> void show(T t) {
System.out.println(t);
}
5、泛型通配符
(1)、无界
"?"表示可以接收任何类型,"?"是类型实参,而不是类型形参。"?"和Number、String、Integer一样都是一种实际的类型。
public void processElements(List<?> elements){
for(Object o : elements){
System.out.println(o);
}
}
(2)、上界
extends表示能够接收A类或者A类的子类。 可以在读元素时候应用,因为元素都是A类或子类,可以放心的用A类拿出。
public void processElements(List<? extends A> elements){
for(A a : elements){
System.out.println(a.getValue());
}
}
(3)、下界
super表示能够接收A类或者A类的父类,可以在添加元素时候应用,因为都是A类或父类,那么就可以安全的插入A类。
public static void insertElements(List<? super A> list){
list.add(new A());
list.add(new B());
list.add(new C());
}
6、instanceof关键字
instanceof是Java的一个二元操作符,类似于 ==,>,< 等操作符。instanceof是Java的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean的数据类型。
obj instanceof Class类
(1)、obj必须为引用类型,不能是基本类型,instanceof运算符只能用作对象的判断。
(2)、如果obj为null,那么将返回false。
(3)、obj为class类的实例对象,返回true。
(4)、obj为class接口的实现类,实现类实例 instanceof 接口返回true,接口引用 instanceof 实现类返回true。
(5)、obj为class类的直接或间接子类返回true。