Java泛型学习笔记
2016-12-16 22:51
281 查看
这是一篇零散的学习笔记,涉及到一些Java泛型遇到的知识点,不是系统学习
在上面的实例中,A是泛型类,而T是泛型参数。
因为擦除,运行时的类型信息就没有了,所以如果不做强制类型转换(显式地或者隐式的),那些需要在运行时知道确切信息的操作都无法进行(方法调用、创建类)。擦除很关键,几乎泛型所有的限制都与擦除这个机制有关。
这里的
这里
看起来截然不同的两个类,其实在创建时都是
其实本质上还是类型擦除的原因,这里明显两个异常类是一样的(运行时都是Object),显示是不行的,所以泛型类是不能继承Throwable及其子类的,而且泛型类也不能被捕获或者抛出。
虽然泛型类不能被抛出,但是这不妨碍类型参数被抛出,只要我们在最初设置一个类型参数的上界即可。
语法糖
泛型算是一种语法糖,本质上和直接存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及其子类的,而且泛型类也不能被捕获或者抛出。
虽然泛型类不能被抛出,但是这不妨碍类型参数被抛出,只要我们在最初设置一个类型参数的上界即可。
相关文章推荐
- java泛型学习笔记
- java泛型学习笔记
- Java泛型学习笔记
- [学习笔记]Java泛型机制(Java 5)
- java学习笔记-java泛型
- JAVA泛型学习笔记
- Java泛型--学习笔记
- Java泛型学习笔记--Java泛型和C#泛型比较学习(一)
- 【09-03】java泛型学习笔记
- Java泛型的学习笔记[1]—基础知识
- Java泛型与反射机制---学习笔记
- 尚硅谷java学习笔记——8.java泛型(Generic)
- JAVA泛型详解 --- 学习笔记
- java泛型学习笔记
- Java泛型学习笔记--Java泛型和C#泛型比较学习(一)
- Win32学习笔记 第四章 输出文本_1
- Win32学习笔记 第三章 HelloWin
- 开发asp.net自定义控件(asp.net学习笔记五)
- Win32学习笔记 第四章 输出文本_2
- Microsoft Agent 学习笔记 (一)