Java中的泛型
来源:互联网 发布:58中国经纪人网络平台 编辑:程序博客网 时间:2024/06/01 08:03
泛型(Generic)在jdk1.5被引入,它加入了一个全新的语法元素,并且好多类和方法都重新实现了泛型的版本,受之影响最大的就是Collections Framework了。本篇博客来讨论一下泛型的语法特征,并简要地讨论一下底层的实现机制。
泛型类
下面先看一个泛型类Printer
public class Printer<T> { T target; public Printer(T target){ this.target = target; } public void print(){ System.out.println(target); }}
这个类的构造函数中接受一个泛型的target,在print方法中可以将它打印出来。这个参数可以是任意的类型。下面看一下如何使用这个类。
public static void main(String[] args) { Printer<String> printer1 = new Printer<String>("hello,generic"); printer1.print(); Printer<Integer> printer2 = new Printer<Integer>(23); printer2.print();}
上面代码的运行结果是
hello,generic23
可以看得出来,泛型的特性加强了Printer的功能,使它可以打印任意类型的东西。
类型推断
泛型支持类型推断。从jdk1.7开始,java编译器是为我们提供一些便利的。以Printer<String> printer1 = new Printer<String>("hello,generic");
为例,可以简化为
Printer<String> printer1 = new Printer<>("hello,generic");
new Printer<>("hello,generic")
返回的类型就是Printer<String>
,因为"hello,generic"
是一个字符串。
<>
被成为diamond操作符,类型推断就是通过这个操作符完成的。
在maven中加入以下配置,即可使用jdk1.7的编译器
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins></build>
泛型方法
在Printer类中加入一个静态的泛型方法staticPrint
public static <T2> void staticPrint(T2 obj) { System.out.println(obj);}
由于是静态方法,所以无需实例化Printer类就可以使用这个方法
Printer.<String>staticPrint("hello,generic");Printer.<Integer>staticPrint(23);
当然,这种情况下也可以使用类型推断
Printer.staticPrint("hello,generic");Printer.staticPrint(23);
这种情况下,连diamond操作符都省略了
bound type
bound type用来对泛型参数做一些限制,即泛型参数必须继承自这个父类,或者实现这个接口。
如果规定Printer类必须是数字,则需要将bound type设置为Number
类,如下
public class Printer<T extends Number> { T target; public Printer(T target) { this.target = target; } public void print() { System.out.println(target); } public static <T2> void staticPrint(T2 obj) { System.out.println(obj); }}
这种情况下,使用String作为泛型参数就不能通过编译了,因为Integer继承自Number类,而String则没有。
// Printer<String>类型不支持// Printer<String> printer1 = new Printer<>("hello,generic");// printer1.print(); Printer<Integer> printer2 = new Printer<Integer>(23); printer2.print();
bound type的机制允许同时声明父类的限制和接口的限制,语法如下
MyClass<T extends MyClass & MyInterface>
泛型类型和通配符
同一个泛型类配上不同的泛型参数,就是不同的类型,即Printer<Integer>
和Printer<String>
在编译时被认为是不同的类型。
看下面的例子
Printer<String> printer1 = new Printer<>("hello,generic");Printer<Integer> printer2 = new Printer<>(23);//printer1 = printer2;
上面代码的最后一行编译时会报错:不兼容的类型:Printer<java.lang.Integer>无法转换为Printer<java.lang.String>
可见,不通的泛型参数之间是不兼容的。但如果我有一个方法需要接受Printer任意泛型参数的对象的话,该如何处理呢?
可以使用通配符来?
解决这个问题
Printer<?> printer3 = null;printer3 = printer1;printer3 = printer2;
也就是说,Printer<?>
类型兼容任意版本的Printer,包括Printer<String>
和Printer<Integer>
。
同时,这个通配符也可以设置bound type。例如,如果将printer3声明为Printer<? extends Integer>
类型的话,是无法将Printer<String>
类型的对象赋值给它的。
Erasure
泛型的一个好处就是它是类型安全的,但这个类型安全是在编译阶段保证的,就像上面的例子一样(不能通过编译)。泛型的所有类型参数都只存在于编译阶段,jvm完全不知道泛型参数的存在,更不知道泛型参数的类型。
java代码编译后,泛型的类型信息会被清除(erase)掉,替换为它的bound type,如果没有指定bound type的话,则默认替换为Object类型,并在必要时做一些恰当的类型转换,java runtime(jvm)完全不知道这一切的存在。这就是java泛型的Erasure机制。
这也解释了为什么不能在泛型方法中创建一个泛型类型的新实例,因为jvm不知道这个泛型类型到底是什么类型。
- Java中的泛型
- Java中的泛型
- Java中的泛型
- java中的泛型
- JAVA 中的泛型
- Java中的泛型
- java中的泛型
- Java中的泛型
- Java中的泛型
- JAVA中的泛型
- java中的泛型
- java中的泛型
- Java中的泛型
- Java中的泛型
- java中的泛型
- java中的泛型
- Java中的泛型
- java中的泛型
- Android Studio无法创建类和接口
- RabbitMQ入门教程(十):队列声明queueDeclare
- 关于二叉树的知识点汇总
- 09.创新机遇来源七:新知识
- 经典题型
- Java中的泛型
- Spring学习之(四)依赖注入的几种装配方式
- 操作符重载
- #448 div.2 B.XK Segments
- “自顶向下,逐步求精“的方法简介
- 51单片机tea5767收音机 红外遥控 自动搜台 存台 DIY
- AES格式保持加密C++实现
- IntelliJ IDEA使用总结
- PAT