TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
本文是Sun官方以Blog形式发布的java核心技术窍门(JavaCoreTechTip)中的一篇,它以非常简洁的示例展示了泛型通配符的使用,初学Java泛型的朋友可以看看。(2009.12.30最后更新)
Java2平台,标准版5.0(J2SE 5.0)为Java程序设计语言及其平台引入了泛型。在最简单的案例和典型的应用中,泛型能够识别集合容器中所存储的是否是你所期望的对象。
所以,你可以特别说你有一个String或其它类型对象的List,而不是声称你的程序有一个Object的List。所以,如果你不小心向该List中加入了错误类型的对象,编译器会告之你这个错误。该错误将在编译时进行修复,而不用等到你运行该程序,且在程序运行到该处代码时,在获取对象的操作中产生一个运行时的强制类型转换异常。
这就提出了泛型的第二个好处。迭代器将变得类型安全了。Iterator接口中的next()方法将会返回集合中下一个元素的类型安全版本。
但这并不是本文要介绍的泛型应用的窍门,那些窍门已由
2005 Core Java Technologies Tip描述过了。在使用泛型时,大多数人都不能很好地理解对extends关键字的使用。一个典型的描述如何使用
extends关键字的示例与绘制图形有关。与其不同的是,此处窍门所用的示例将使用Swing组件,以便你不必创建额外的新类。在一个非常有限的例子中,Swing按钮组件的类层次结构如下所示,当然,Object是实际上的根。
Component
|-
Container
|-
JComponent
|-
AbstractButton
|-
JButton
|-
JMenuItem
|-
JCheckBoxMenuItem
|-
JMenu
|-
JRadioButtonMenuItem
|-
JToggleButton
|-
JCheckBox
|-
JRadioButton
所有AbstractButton的子类都共同享有的一个东西就是方法getText。这就是泛型的精髓,你能定义一个方法去处理以AbstractButton为元素的List,并返回这些按钮的String类型的标签的List。下面是该方法的第一个版本:
public
static
List
<
String
>
getLabels(List
<
AbstractButton
>
list) {
List
<
String
>
labelList
=
new
ArrayList
<
String
>
(list.size());
for
(AbstractButton button: list) {
labelList.add(button.getText());
}
return
labelList;
}
下面就是如何使用该方法。首先,定义一个AbstractButton类型的List,然后向其中填充值,并调用该方法:
List
<
AbstractButton
>
buttonList
=
new
ArrayList
<
AbstractButton
>
();
buttonList.add(
new
JButton(
"
Hello
"
));
buttonList.add(
new
JCheckBox(
"
World
"
));
buttonList.add(
new
JRadioButton(
"
Hola
"
));
buttonList.add(
new
JMenuItem(
"
Mundo
"
));
List labels
=
getLabels(buttonList);
System.out.println(labels);
根据Google,"Hola, Mundo"是"Hello, World"的西班牙译文。调用println()方法的结果如下所示:
[Hello, World, Hola, Mundo]
对于
AbstractButton的
List对象,一切都能正常运行,但当是其它类型,特别是AbstractButton子类型的List时,就不能正常工作了。从逻辑上,有人可能认为对于以JButton为元素的List,一切仍能正常工作。因为JButton是AbstractButton的子类。难道不能对AbstractButton子类型的List调用方法
getLabels(List<AbstractButton>)?
然而,事实并非如此。因为这是一个编译时检查,同时也因为getLabels方法被定义为只接受AbstractButton的List,你不能向该方法中传入任何其它类型的List。
GetList.java:
13
: getLabels(java.util.List
<
javax.swing.AbstractButton
>
)
in GetList cannot be applied to (java.util.List
<
javax.swing.JButton
>
)
List
<
String
>
labels
=
getLabels(buttonList);
^
1
error
这也就是extends关键字发挥作用的地方了。不将getLabes方法定义为仅仅接受AbstractButton List,而是将它定义为接受AbstractButton子类的List:
public
static
List
<
String
>
getLabels(
List
<?
extends
AbstractButton
>
list)
此处的通配符?表明该方法并不关心确切的类型是什么,只要它是AbstractButton的子类型即可。下面是综合了前述所有代码片断的完整示例程序:
import
java.util.
*
;
import
javax.swing.
*
;
public
class
GetList {
public
static
void
main(String args[]) {
List
<
JButton
>
buttonList
=
new
ArrayList
<
JButton
>
();
buttonList.add(
new
JButton(
"
Hello
"
));
buttonList.add(
new
JButton(
"
World
"
));
buttonList.add(
new
JButton(
"
Hola
"
));
buttonList.add(
new
JButton(
"
Mundo
"
));
List labels
=
getLabels(buttonList);
System.out.println(labels);
}
public
static
List
<
String
>
getLabels(
List
<?
extends
AbstractButton
>
list) {
List
<
String
>
labelList
=
new
ArrayList
<
String
>
(list.size());
for
(AbstractButton button: list) {
labelList.add(button.getText());
}
return
labelList;
}
}
现在,当你要用泛型来定义你自己的类和方法时,就要考虑接受作为泛型参数的抽象类,或它的任一超类,记得使用通配符以便相同的方法对于子类也能很好地工作。
更多关于泛型的信息,请见两篇较早前由Gilad Bracha撰写的教程:一篇是
2004年的教程(PDF),另一篇是在线的
Java Tutorial中的泛型章节。
|
|