Java5的泛型的语法,已经有很多帖子讲了,这里依据我的一些个人理解做一次总结,一方面是为了将我近一段时间对泛型的学习落实到纸面,毕竟有很多想 法,如果只是存在于脑子里,过一段时间也就淡忘了,总要留下点文字便于以后回顾;另一方面,也希望拿出点东西来与大家交流分享,这样才能不断的得到提高。
A。同类型赋值:
B。超类型赋值:
可赋值的超类型可以是原类型的任何超类型或者接口,这些赋值都是类型安全的,不会引发任何编译时警告。例如:
C。子类型赋值:
D。赋值给传统代码(row type赋值):
E。传统代码(row type)赋值给泛型
与第三点:子类型赋值类似,可以将传统代码看做是ValueHolder<? extends Object>,同样需要强类型转换,以及存在类型安全问题。
泛型是什么
简单的来说,泛型可以认为是类型参数化的技术。相对于类型的参数化,在传统的java代码中,我们可以理解为所有的参数都是值的参数化,例如以下代码:
1
package
org.dbstar.generic;
2
3 public class ValueHolder {
4 private String value;
5
6 public ValueHolder(String value) {
7 this .value = value;
8 }
9
10 public String getValue() {
11 return value;
12 }
13
14 public void setValue(String value) {
15 this .value = value;
16 }
17 }
其中的成员变量、构造函数参数和方法参数,都可以认为是值的参数化的体现。但是,不管值如何变化,值的类型只能局限于String及其子类,如果我们想让 ValueHolder同时也能持有一个Integer类型的值,那么在传统的Java代码中,只能将成员变量的类型定义为Object,如下:
2
3 public class ValueHolder {
4 private String value;
5
6 public ValueHolder(String value) {
7 this .value = value;
8 }
9
10 public String getValue() {
11 return value;
12 }
13
14 public void setValue(String value) {
15 this .value = value;
16 }
17 }
1
package
org.dbstar.generic;
2
3 public class ValueHolder {
4 private Object value;
5
6 public ValueHolder(Object value) {
7 this .value = value;
8 }
9
10 public Object getValue() {
11 return value;
12 }
13
14 public void setValue(Object value) {
15 this .value = value;
16 }
17 }
使用Object版的ValueHolder的代码看起来会像这样:
2
3 public class ValueHolder {
4 private Object value;
5
6 public ValueHolder(Object value) {
7 this .value = value;
8 }
9
10 public Object getValue() {
11 return value;
12 }
13
14 public void setValue(Object value) {
15 this .value = value;
16 }
17 }
1
public
static
void
main(String[] args) {
2 ValueHolder vhi = new ValueHolder( new Integer( 1 ));
3 ValueHolder vhs = new ValueHolder( " abc " );
4 ValueHolder vho = new ValueHolder( new Object());
5 System.out.println( " ValueHolder of Integer= " + vhi.getValue());
6 System.out.println( " ValueHolder of String= " + vhs.getValue());
7 System.out.println( " ValueHolder of Object= " + vho.getValue());
8 }
输出结果为:
2 ValueHolder vhi = new ValueHolder( new Integer( 1 ));
3 ValueHolder vhs = new ValueHolder( " abc " );
4 ValueHolder vho = new ValueHolder( new Object());
5 System.out.println( " ValueHolder of Integer= " + vhi.getValue());
6 System.out.println( " ValueHolder of String= " + vhs.getValue());
7 System.out.println( " ValueHolder of Object= " + vho.getValue());
8 }
1
ValueHolder of Integer
=
1
2 ValueHolder of String = abc
3 ValueHolder of Object = java.lang.Object@757aef
幸运的是,Java5给我们提供了一个将value的类型也作为一个参数来设置的方法,那就是泛型,下面是将value的类型也参数化后的 ValueHolder实现:
2 ValueHolder of String = abc
3 ValueHolder of Object = java.lang.Object@757aef
1
package
org.dbstar.generic;
2
3 public class ValueHolder < E > {
4 private E value;
5
6 public ValueHolder(E value) {
7 this .value = value;
8 }
9
10 public E getValue() {
11 return value;
12 }
13
14 public void setValue(E value) {
15 this .value = value;
16 }
17 }
其中,value就是值的参数化,value的类型现在定义为E,<E>就是类型的参数化。使用ValueHolder的代码也相应发生了变 化:
2
3 public class ValueHolder < E > {
4 private E value;
5
6 public ValueHolder(E value) {
7 this .value = value;
8 }
9
10 public E getValue() {
11 return value;
12 }
13
14 public void setValue(E value) {
15 this .value = value;
16 }
17 }
1
ValueHolder
<
Integer
>
vhi
=
new
ValueHolder
<
Integer
>
(
new
Integer(
1
));
2 ValueHolder < String > vhs = new ValueHolder < String > ( " abc " );
3 ValueHolder < Object > vho = new ValueHolder < Object > ( new Object());
4 System.out.println( " ValueHolder of Integer= " + vhi.getValue().intValue());
5 System.out.println( " ValueHolder of String= " + vhs.getValue().substring( 1 ));
6 System.out.println( " ValueHolder of Object= " + vho.getValue());
根据ValueHolder类型定义的不同,类型参数<E>在不同场合代表了不同的实际类型。
2 ValueHolder < String > vhs = new ValueHolder < String > ( " abc " );
3 ValueHolder < Object > vho = new ValueHolder < Object > ( new Object());
4 System.out.println( " ValueHolder of Integer= " + vhi.getValue().intValue());
5 System.out.println( " ValueHolder of String= " + vhs.getValue().substring( 1 ));
6 System.out.println( " ValueHolder of Object= " + vho.getValue());
泛型的赋值
与值参数的赋值不同的是,类型参数的赋值有其特殊性,下面来逐一说明:A。同类型赋值:
1
ValueHolder
<
Integer
>
vhi
=
new
ValueHolder
<
Integer
>
(
new
Integer(
1
));
2 ValueHolder < Integer > vhi2 = vhi;
3 vhi2.setValue( new Integer( 2 ));
4 System.out.println( " ValueHolder of Integer2= " + vhi2.getValue().intValue());
这种赋值后的变量,与源变量具有完全一致的操作,包括获取泛型变量和在方法参数中设置泛型变量。
2 ValueHolder < Integer > vhi2 = vhi;
3 vhi2.setValue( new Integer( 2 ));
4 System.out.println( " ValueHolder of Integer2= " + vhi2.getValue().intValue());
B。超类型赋值:
1
ValueHolder
<
Integer
>
vhi
=
new
ValueHolder
<
Integer
>
(
new
Integer(
1
));
2 ValueHolder < Number > vhi3 = vhi; // 实际上,这是不允许的,会导致编译错误
3 ValueHolder <? extends Number > vhi2 = vhi; // 必须要这样写
4 System.out.println( " ValueHolder of Integer2= " + vhi2.getValue().intValue());
5 vhi2.setValue( new Integer( 2 )); // 超类型赋值后,操作受到限制,会导致编译错误
6 vhi2.setValue( null ); // 只有设置null值才是合法的,其他值一概不允许设置
这种赋值后的变量,能调用返回值为泛型变量的方法,但是只能使用新泛型变量类型的方法,而不能再使用原有泛型变量类型上的方法,这样说有点绕,举例来说, 上面的vhi2就只能使用Number类型上定义的方法,而无法再使用原先在Integer类型上定义的方法了。
2 ValueHolder < Number > vhi3 = vhi; // 实际上,这是不允许的,会导致编译错误
3 ValueHolder <? extends Number > vhi2 = vhi; // 必须要这样写
4 System.out.println( " ValueHolder of Integer2= " + vhi2.getValue().intValue());
5 vhi2.setValue( new Integer( 2 )); // 超类型赋值后,操作受到限制,会导致编译错误
6 vhi2.setValue( null ); // 只有设置null值才是合法的,其他值一概不允许设置
可赋值的超类型可以是原类型的任何超类型或者接口,这些赋值都是类型安全的,不会引发任何编译时警告。例如:
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
ValueHolder
<?
extends
Number
>
vhn
=
vhi;
//
超类
2 ValueHolder <? extends Object > vho2 = vhi; // 超类
3 ValueHolder <? extends Comparable > vhc = vhi; // 接口
赋值后的带?的泛型,还能继续赋值给超类,例如:
2 ValueHolder <? extends Object > vho2 = vhi; // 超类
3 ValueHolder <? extends Comparable > vhc = vhi; // 接口
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->
1
ValueHolder
<?
extends
Number
>
vhn
=
vhi;
2 ValueHolder <? extends Object > vho3 = vhn;
ValueHolder<?>等效于ValueHolder<? extends Object>,因为Object是所有类的超类。
2 ValueHolder <? extends Object > vho3 = vhn;
C。子类型赋值:
1
ValueHolder
<?
extends
Number
>
vhi2
=
vhi;
//
必须要这样写
2 @SuppressWarnings( " unchecked " )
3 ValueHolder < Integer > vhi3 = (ValueHolder < Integer > ) vhi2;
和值参数的赋值一样,超类型的泛型变量往子类型的泛型变量赋值,需要强制转换,转换后的vhi3与vhi具有完全一致的操作。但是,需要注意的一点是,这 种转换会导致一个unchecked的编译时警告,而且,若无法完成转换,会导致一个运行时的ClassCastException异常,例如:
2 @SuppressWarnings( " unchecked " )
3 ValueHolder < Integer > vhi3 = (ValueHolder < Integer > ) vhi2;
1
@SuppressWarnings(
"
unchecked
"
)
2 ValueHolder < Double > vhi3 = (ValueHolder < Double > ) vhi2; // 这里不会抛出异常
3 vhi3.setValue( new Double( 12.5 ));
4 System.out.println( " ValueHolder of Double= " + vhi3.getValue().doubleValue());
5 System.out.println( " ValueHolder of Integer= " + vhi.getValue().intValue()); // 会在这里抛出ClassCastException
上例中,vhi2将Integer类型转换成了超类型Number,而vhi3又将Number强类型转换成了Double,这也是允许的,不会引发编译 时错误或者运行时错误。下面甚至还可以给vhi3设置一个Double的值,值得注意的是,vhi3其实就是vhi,我们给一个Integer的变量设置 了一个Double的值,却没有引发任何异常,还真是诡异的很。随后,我们在调用vhi.getValue().intValue()时,才终于引发了 ClassCastException。由此可见,这种强类型转换有时候会使错误变得非常隐晦难于发现,我们应该尽量避免这种转换的使用。
2 ValueHolder < Double > vhi3 = (ValueHolder < Double > ) vhi2; // 这里不会抛出异常
3 vhi3.setValue( new Double( 12.5 ));
4 System.out.println( " ValueHolder of Double= " + vhi3.getValue().doubleValue());
5 System.out.println( " ValueHolder of Integer= " + vhi.getValue().intValue()); // 会在这里抛出ClassCastException
D。赋值给传统代码(row type赋值):
1
@SuppressWarnings(
"
unchecked
"
)
2 ValueHolder vh = vhi;
3 vh.setValue( new Integer( 3 ));
不指定类型参数的泛型类,称之为row type,这是Java5泛型为了与老版本的代码兼容而选择的一种处理方式。Row type的泛型类中,所有的类型参数都被当做Object来处理,也就是说,ValueHolder可以当做 ValueHolder<Object>来处理,但是与ValueHolder<Object>又有所不同,因为 ValueHolder<Integer>是不能被转换为ValueHolder<Object>的,而能转换的ValueHolder<? extends Object>又不能调用setValue方法(当然可以设置null值,而其他非null值不能设置)。值得注意的是,转换到传统代码,以及使用 传统代码调用有泛型参数的方法,会引起一个unchecked的编译时警告。
2 ValueHolder vh = vhi;
3 vh.setValue( new Integer( 3 ));
E。传统代码(row type)赋值给泛型
与第三点:子类型赋值类似,可以将传统代码看做是ValueHolder<? extends Object>,同样需要强类型转换,以及存在类型安全问题。