Java语言基础特性—第一部分(下)
来源:互联网 发布:javascript var 数组 编辑:程序博客网 时间:2024/05/17 08:36
你可以通过指定extends
后接类型名称来提供通配符的上界。同样的,你可以通过指定super
后接类型名称来提供通配符的下界。这些限定限制了可以作为实际类型参数传入的类型。
在例子中,你可以把? extends String
理解为任何String或其子类的实际类型参数。同样的,你可以把? super String
理解为任何String或其父类的实际类型参数。因为String是final的,这意味着它不能被继承,只有源列表为String对象,目标列表为String或Object对象能够传入作为参数,这样用处不大。
你可以使用泛型方法来完全解决这个问题,它是一个有类型实现参数的类或接口方法。泛型方法支持下面的语法:
<formalTypeParameterList> returnType
identifier(parameterList)
泛型方法的形参列表在它的返回类型之前。它包含类型参数和可选的上界。类型参数可以作为返回类型使用,并且可以出现在参数列表中。
清单9展示了怎么定义和调用泛型copy()
方法
Listing 9. GenDemo.java (version 5)
importjava.util.ArrayList;
importjava.util.List;
publicclass GenDemo
{
publicstatic void main(String[] args)
{
List<Integer>grades = newArrayList<Integer>();
Integer[]gradeValues =
{
newInteger(96),
newInteger(95),
newInteger(27),
newInteger(100),
newInteger(43),
newInteger(68)
};
for(inti= 0; i < gradeValues.length; i++)
grades.add(gradeValues[i]);
List<Integer>failedGrades = newArrayList<Integer>();
copy(grades,failedGrades, newFilter<Integer>()
{
publicboolean accept(Integer grade)
{
returngrade.intValue()<= 50;
}
});
for(inti= 0; i < failedGrades.size(); i++)
System.out.println(failedGrades.get(i));
}
static<T>voidcopy(List<T> src, List<T> dest,
Filter<T> filter)
{
for(inti= 0; i < src.size(); i++)
if(filter.accept(src.get(i)))
dest.add(src.get(i));
}
}
interfaceFilter<T>
{
booleanaccept(T o);
}
清单9中我定义了一个<T> void copy(List<T> src, List<T> dest, Filter<T> filter)
泛型方法。编译器注意到src
,dest
和filter
参数的类型都包含类型参数T。这意味着在方法调用中必须传入同样的实际类型参数,而编译器会在调用中获取参数。
如果你编译清单9(javac GenDemo.java
)并运行程序(java GenDemo
),你应该可以看到下面的输出:
27
43
Java语言中关于泛型最有争议的是什么?
虽然泛型本身并不具争议,但它在Java语言中的特殊实现却是。泛型是作为消除转换的语法糖的编译时特性来实现的。编译器会在编译源码后丢弃泛型类型或泛型的形参类型列表。这个“丢弃”行为称为擦除(erasure)。其他在泛型中关于擦除的例子包含:在代码类型不正确时,插入时可以自动转换为合适的类型;通过上界(例如Object
)来替换类型参数。
更多关于泛型的讨论
泛型不只因为擦除而备受争议。看一下StackOverflow.com的“为什么我们抱怨Java关于泛型的实现很糟糕”主题的讨论,包含了通配符很难理解和事实上泛型并不直接值类型(例如,你不能指定
List<int>
)。
使用擦除会有下面的几个限制:
instanceof
并不能用于参数化类型,只有一种情况是例外的。这个例外就是无界的通配符。例如,你不能指定Set<Shape> shapes = null; if (shapes instanceof ArrayList<Shape>){}
。相反,你需要把对instanceof
表达式修改为shapes instanceof ArrayList<?>
,这种就是无界的通配符。或者,你可以指定shapes instanceof ArrayList
,这使用的是原生类型(通常也是推荐使用的做法)。编译器把泛型代码转换为非泛型代码,并保存在class文件中。一些开发人员指出擦除会使得你不能通过反射取得泛型信息,因为它们并不保存在class文件中。开发人员Jakob Jenkov在“Java 反射:泛型”中指出一些泛型信息会被保存在class文件中的情况,并且这些信息可以通过反射来访问。
你不能在创建数组的表达式中使用类型参数;例如,
elements = new E[size];
。如果你这样做,编译器会报告泛型数组创建错误信息。
鉴于擦除的限制,你会奇怪为什么泛型要通过擦除来实现。原因很简单:Java编译器被重构来使用擦除,因此泛型代码可以跟那些非泛型的遗留代码进行交互。没有这个向后兼容性,遗留代码在支持泛型的Java编译器上编译时将会报错。
第一部分总结
Java语言已经添加了许多新特性。在这篇文章中,我展示了怎么使用断言来增强你在代码正确性上的信心,和如何使用泛型来消除ClassCastException
。通过使用断言和泛型,你可以编写更可靠的代码,并且使你的代码在运行时的错误降到最低,当然,也减少面对生气的客户时的头痛了。
Java 5 是Java平台历史上的一个重大发布,虽然泛型比其他特性都更具争议,但它却比其他都更加重要。我的下篇文章将会介绍另外7个在Java5时加入的必要的特性:类型安全的枚举,注解,自动装箱和拆箱,加强的循环,静态引入,可变参数,协变返回类型。在那之前,下载这篇文章的源代码,它包含了更多的关于断言和泛型的提示和例子。
Jeff Friesen是一个自由职业导师和侧重Java和Android的软件开发人员。除了为Apress写Java和Android书籍,Jeff为JavaWorld,informIT,Java.net,DevSource和SitePoint写了大量的关于Java和其他技术的文章。你可以通过他在TutorTutor.ca的网站联系到他
了解更多主题相关
下载文章的源代码
阅读Angelika Langer的Java Generics FAQs,那里有着大量的关于Java语言泛型的信息和观点。
对于想学习Java语言和它的备受争议的特性的,Langer的文章理解闭包的争论(2008.6 JavaWorld)对比了Java 7语言中的三个关于添加闭包和lambda表达式的初始提议。
可以查看“Java反射:泛型”(Jakob Jenkov, Jenkov.com)关于泛型反射和某些情况下可以在运行时获取泛型信息的讨论。
Java无痛并发编程,第一部(2013.6):介绍了Executor框架,同步类型和Java并发集合包。
Java无痛并发编程,第二部(2013.8):介绍了锁,原子变量和fork/join操作,还附加了Java8中关于java.util.concurrent
的修改概述。
跟上Java Date和Time API(2013.4):介绍了Java8的JSR310:Date 和Time API,并且展示了你最有可能使用的java.time
系列类的使用。
JavaWorld中更多关于Java集合框架的文章:
Java集合框架从零开始(1998.11 Dan Becker):这篇文章介绍了集合刚引入java时的历史。
Java集合中的省时习惯(2013.9 Java Q&A blog):展望未来,Jeff Friesen回答一些当前使用Java集合的常见问题。
- Java语言基础特性—第一部分(下)
- Java语言基础特性—第一部分(上)
- Java语言基础特性—第一部分(中)
- Java语言基础特性——第二部分
- 第一部分:Java语言的基础组成
- Java基础部分-《第一部分》
- 第一部分 Go 语言基础
- JAVA基础——常用语句格式(第一部分)
- java语言特性基础
- java基础问题(第一部分)
- java基础部分总结第一部分
- java语言基础----(特性方面)
- java语言基础部分(1)——常用关键字
- JAVA面试精选【Java基础第一部分】
- JavaScript基础(第一部分)
- C语言——第一部分 C语言概述以及编程基础
- Java修炼 之 基础篇(一)Java语言特性
- Java修炼 之 基础篇(一)Java语言特性
- 汇编比赛--情定迷宫
- mysql的日期时间函数小汇总(2)
- NoSQL非关系型数据库 笔记
- window平台安装ant
- 条件变量
- Java语言基础特性—第一部分(下)
- 黑马程序员.Android攻城狮.JAVA基础.1.4.Java异常
- 005寻找满足和为定值的两个或多个数
- extjs grid内容显示居中代码
- cocos2d-x中精灵移动
- 【Android】神奇的android:clipChildren属性
- 数据库连接池浅析
- MINA框架简介
- Android NDK开发-----示例