Java:泛型(一)
泛型
泛型是实现代码复用的重要手段,在Java集合类框架中泛型被广泛应用,本文介绍Java中泛型的概念及基本使用。
泛型作用于编译前的静态类型检查,也就是说运行时JVM中实际上是没有泛型这种东西的,因为在运行前会进行类型擦除。泛型的使用让Java代码的复用变得方便,安全,规范,使静态类型检查在Object对象上也有了用武之地(使静态类型检查更有用处)
泛型类
我们有这样一个类
public class Box{
public String object;
public void set(String object){this.object = object;}
public String get(){return object;}
}
这是一个简单的容器类,现在我们可以把String类的对象放入,取出,
但如果我需要其他类型的容器,又要重写一个Box类,于是有了下面的容器类
public class Box{
public Object object;
public void set(Object object){this.object = object;}
public Object get(){return object;}
}
上面这个代码基本上满足需求,但是如果不做标识,我们无法区分当前容器中装的到底是什么类型的对象,给取出数据后的转型带来麻烦,各种没有关系的对象都能放入一个集合,为了规范化,在Java1.5后,我们使用泛型
public class Box<T>{
public T object;
public void set(T object){this.object = object;}
public T get(){return object;}
}
其中 T 是一个标志符,表示一种Type,写在类上的泛型T说明类中所有的T都表示同一类型,及作用域在整个类上
通过泛型,Box类得到了复用,我们可以制造存放各种对象的Box
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<>();这里可以看出,已知的泛型类型是可以省略不写的,IDEA中也默认隐藏
Box objectBox = new Box();
注意,假设 Teacher 类与 Student 类继承于 Person 类,由于Java的泛型实现机制,并不存在Box<Teacher>、Box<Student>、Box<Person>类型,因此Box<Teacher>、Box<Student>类型的变量与Box<Person>的变量之间不具有继承关系
参见Java:泛型中的类型擦除
泛型接口
接口是一种特殊的类,所以泛型在接口中的应用参考泛型类(这一条就这样水过去了)
泛型方法
定义了自己的泛型类型的方法才叫泛型方法
同样,定义在方法上的泛型类型,作用域也只在该方法上
仅仅使用类上的泛型的方法不称为泛型方法
public class Pair<K,V>{
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
public K getKey() { return key; }
public void setKey(K key) { this.key = key; }
public V getValue() { return value; }
public void setValue(V value) { this.value = value; }
public boolean isEqual(Pair<K,V> p){
return this.key == p.key && this.value == p.value;
}
}
上面的这个isEqual方法中的K,V访问的是类上的泛型,所以下图产生编译期异常
因为调用者p1的类型在静态类型检查中为Pair<Integer, String>,所以p1.isEqual接受的参数只能是Pair<Integer, String>,是不通用的,这也是使用类上定义的泛型的方法不称为泛型方法的原因,因为这种"泛型"是被类上的泛型固定住的类型,随着调用对象的泛型类型的改变而改变,属于类泛型的范畴
所以泛型方法应当这样定义
[作用域修饰符] <泛型类型标识> [返回类型] 方法名称(参数列表){}
其实就是在返回值类型前加上泛型类型说明
public <U,T> boolean isEqual(Pair<U,T> p){
return this.key == p.key && this.value == p.value;
}
为了区分,这里用U、T作为该泛型方法的泛型名称。ps:泛型类型定义与变量一样,后定义的变量会隐藏先前定义的作用域更大的同名变量
可以看到报错已经消失
可以在这里添上正确的泛型标识,IDEA默认隐藏,是否写出看个人喜好,因为即使忘记方法使用了泛型,静态类型检查也会提示我们
请移步 Java:泛型(二)
2018/11/25