目录
?泛型的向上转型
将静态方法的泛型类型和实例类型的泛型类型区分开
多泛型类
java可以创建泛型数组(待完善)
Java实现泛型的方法——擦拭法
由此,Java泛型的局限也体现出来
泛型继承(loading)
通配符(loading)
泛型与反射(loading)
总结自廖雪峰老师的Java教程:?
Java教程 - 廖雪峰的官方网站 (liaoxuefeng.com)https://www.liaoxuefeng.com/wiki/1252599548343744?
?泛型的向上转型
在Java标准库中,? ArrayList<T>实现了List<T>接口,它可以向上转型为List<T>:
public class ArrayList<T> implements List<T> {
...
}
List<String> list = new ArrayList<String>();
编译器看到泛型类型List<String>就可以自动推断出后面的ArrayList<T>的泛型类型必须是ArrayList<String>,代码可以简写为:
// 可以省略后面的Number,编译器可以自动推断泛型类型:
List<Number> list = new ArrayList<>();
?
!注意:不能把ArrayList<Integer> 向上转型为ArrayList<Number> 或List<Number> 。
👇
假设ArrayList<Integer> 向上转型为ArrayList<Number> :
// 创建ArrayList<Integer>类型:
ArrayList<Integer> integerList = new ArrayList<Integer>();
// 添加一个Integer:
integerList.add(new Integer(123));
// “向上转型”为ArrayList<Number>:
ArrayList<Number> numberList = integerList;
// 添加一个Float,因为Float也是Number:
numberList.add(new Float(12.34));
// 从ArrayList<Integer>获取索引为1的元素(即添加的Float):
Integer n = integerList.get(1); // ClassCastException!
- 一个ArrayList<Integer>转型为ArrayList<Number>类型后,这个ArrayList<Number>就可以接受Float类型,因为Float是Number的子类。
- 而numberList?实际上和integerList?是同一个对象(ArrayList<Integer>类型),不可能接受Float类型, 在获取Integer的时候将产生ClassCastException。
总结:
编译器为了避免这种错误,根本就不允许把ArrayList<Integer>转型为ArrayList<Number>。
!注意泛型的继承关系:可以把ArrayList<Integer>向上转型为List<Integer>(T不能变),但不能把ArrayList<Integer>向上转型为ArrayList<Number>(T不能变成父类)
▲另外须知: ArrayList<Integer>和ArrayList<Number>两者完全没有继承关系。
?
将静态方法的泛型类型和实例类型的泛型类型区分开
注意,泛型类型不能用于静态方法
下面的代码编译错误
public class Pair<T> {
private T first;
private T last;
public Pair(T first, T last) {
this.first = first;
this.last = last;
}
public T getFirst() { ... }
public T getLast() { ... }
// 对静态方法使用<T>:
public static Pair<T> create(T first, T last) {
return new Pair<T>(first, last);
}
}
?👇正确表示如下
public class Pair<T> {
private T first;
private T last;
public Pair(T first, T last) {
this.first = first;
this.last = last;
}
public T getFirst() { ... }
public T getLast() { ... }
// 静态泛型方法应该使用其他类型区分:
public static <K> Pair<K> create(K first, K last) {
return new Pair<K>(first, last);
}
}
多泛型类
class Pair<T,K>
{
private T first;
private K second;
public Pair(T first, K second){
this.first = first;
this.second = second;
}
public T getFirst(){
return this.first;
}
public K getSecond(){
return this.second;
}
}
public class pairx {
public static void main(String[] args) {
Pair<String, Integer> p1 = new Pair<>("泥烟", 8080);
System.out.println(p1.getFirst()+p1.getSecond());
}
}
运行结果:
输出→?泥烟8080?
另外java是可以创建泛型数组的(还未完全掌握,之后完善):
java可以创建泛型数组(待完善)
Java中创建泛型数组 - minghai - 博客园 (cnblogs.com)https://www.cnblogs.com/minghaiJ/p/11259318.html
Java实现泛型的方法——擦拭法
Java的泛型是由编译器在编译时实行的,编译器内部永远把所有类型T 视为Object 处理,但是,在需要转型的时候,编译器会根据T 的类型自动为我们实行安全地强制转型。
由此,Java泛型的局限也体现出来
局限一:<T> 不能是基本类型,例如int ,因为实际类型是Object ,Object 类型无法持有基本类型:
Pair<int> p = new Pair<>(1, 2); // compile error!
?局限二:无法取得带泛型的Class
有如下类
class Pair<T> {
private T first;
private T last;
public Pair(T first, T last) {
this.first = first;
this.last = last;
}
public T getFirst() {
return first;
}
public T getLast() {
return last;
}
}
Pair<String> p1 = new Pair<>("Hello", "world");
Pair<Integer> p2 = new Pair<>(123, 456);
Class c1 = p1.getClass();
Class c2 = p2.getClass();
System.out.println(c1==c2); // true
System.out.println(c1==Pair.class); // true
?
无论T 的类型是什么,getClass() 返回同一个Class 实例,因为编译后它们全部都是Pair<Object> ?
局限三:无法判断带泛型的类型,原因同上
Pair<Integer> p = new Pair<>(123, 456);
// Compile error:
if (p instanceof Pair<String>) {
...
}
并不存在Pair<String>.class,而是只有唯一的Pair.class
局限四:不能直接实例化T 类型?
public class Pair<T> {
private T first;
private T last;
public Pair() {
// Compile error:
first = new T();
last = new T();
}
}
擦拭后实际上变成了:
first = new Object();
last = new Object();
将其实例化的方法
?(待续...)
泛型继承(loading)
通配符(loading)
泛型与反射(loading)
|