您的位置:首页 > 编程语言 > Java开发

Java泛型学习笔记

2016-12-16 22:51 281 查看
这是一篇零散的学习笔记,涉及到一些Java泛型遇到的知识点,不是系统学习

语法糖

 泛型算是一种语法糖,本质上和直接存Object是一样的,只不过通过泛型,编译器会对这个类做一个类型转换,能将问题发现在编译期。

区分:泛型类和类型参数

class A<T>{
T t;
}


 在上面的实例中,A是泛型类,而T是泛型参数。

擦除

 前面说到,泛型是一种语法糖,所以在虚拟机中,是没有泛型这个概念的,所以在编译时,编译器会把这些泛型参数转为其限定类型(如果没有限定上界,那就是Object),就叫做擦除。

 因为擦除,运行时的类型信息就没有了,所以如果不做强制类型转换(显式地或者隐式的),那些需要在运行时知道确切信息的操作都无法进行(方法调用、创建类)。擦除很关键,几乎泛型所有的限制都与擦除这个机制有关。

通配符

 前面说了通配符的概念,大概就是
<? extends BoundingType>
或者
<? super BoundingType>
这个BoudingType就叫做上界或者下界
?
就叫做通配符。表示某个类的子类或者某个类的父类。这样的限定类型是可以用在定义和申明时的。下面一段代码说明了类的定义、申明和创建三个阶段。

public class A<? extends B>{

public static void main(String[] args){

List<? extends B> lists = new ArrayList<>();

}
}


 这里的
class A...
就是类的定义部分,而
List<? extends B> lists
是对List这个类进行申明,而
new ArrayList<>()
是对类的创建部分。基本上,通配符在定义时的作用是限制子类或者在定义是确定参数类型(并给其确定一个限定上界/下界),通配符在申明时的作用是限定在创建确定类型参数(注意这个参数的限定上界仍然是在定义时确定的)。

菱形语法:Java7特性

 如果在创建某个类时,申明类时确定了类型参数,那么创建中就不必再申明具体的类型参数,如之前的代码中,

List<? extends B> lists = new ArrayList<>();


 这里
ArrayList<>()
中是
<>
而不是
<B>
之类的,是因为在申明时就从语法上(没错加粗是因为我还是要强调其实本质上在运行时还是Object或者是限定类型),能确定这个类型参数了。注意这个要在Java7及以上用。

泛型类的数组初始化不合法

 根本原因是,数组在创建的时候必须知道内部元素的类型,而且一直都会记得这个类型信息。而泛型类在创建时是不能确定类型的,考虑下面的例子:

List<String>[];
List<Integer>[];


 看起来截然不同的两个类,其实在创建时都是
List[](List<Object>[])
,所以因为参数类型不能确定,所以数组不支持初始化。但是可以通过强制类型转换的方式的生成数组,例如如下的代码

//错误
// List<String>[] list1 = new List<String>[2];
//正确
List<String>[] list2 = (List<String>[]) new List[2];


参数化类型不能做需要运行时信息的事情

 这个之前有所提到,即擦除的限制。比如下面的操作是非法的

public class A<T>{

public static void main(String[] args){
//直接通过new初始化不行
//T t = new T();
//调用不行,除非做了强制类型转换
//t.say();
}
}


参数化类型作为静态上下文

 静态上下文指的是,静态成员变量、静态代码块、静态方法。下面一段代码也是非法的。因为多个类都会共用这些静态的上下文,不同的实例申明创建时对待T可能是不同类型,这意味这就需要在编译时插入不同的类型转换代码,从而导致错误。

public class A<T> {

//非法
private static T t;

//非法
static{
T t;
}

//非法
public static void f(){
T t;
}

}


泛型与异常

 泛型类是不能继承Throwable及其子类的,具体原因看下面这个例子:

//这段代码是错误的
try {
doSomeStuff();
} catch (SomeException<Integer> e) {
// ignore that
} catch (SomeException<String> e) {
}


 其实本质上还是类型擦除的原因,这里明显两个异常类是一样的(运行时都是Object),显示是不行的,所以泛型类是不能继承Throwable及其子类的,而且泛型类也不能被捕获或者抛出。

 虽然泛型类不能被抛出,但是这不妨碍类型参数被抛出,只要我们在最初设置一个类型参数的上界即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: