版权所有,转载请注明出处
本文关键字:Generics 泛型 java泛型
Generic只是提供在编译的时候提供一个类型信息,告诉编译器与某个类(如List)相关的是String型还是Double型等信息,编译时会检查调用该类中的方法时所用的类型和返回的类型是否与该类相关的类型一致,编译后的代码并无特别之处.
特别注意:Java中引入泛型只是编译时检查,而且主要是检查调用泛型类的类,运行时并不检查,与1.4版的一样
例如A类为泛型类,B类调用A类的方法,编译时将会检查B类的调用是否符合类型转换要求.对A类来说泛型类T来说具体为什么类型,是不确定的,可以看作是当Object来处理的,而且对T赋予什么对象都会出现warn,但可正常运行.
如:对于泛型类(以下称A):
package com.sily;
import java.util.ArrayList;
import java.util.List;
public class GenericClassA<T> {
public T p(T c) {
T t = (T) (new Double(23));
System.out.println(c + " " + c.getClass()+ " " + t);
return c;
}
public T d() {
T t = (T) (new Double(23));
return t;
}
public List<String> l() {
return new ArrayList<String>();
}
/**
* @param args
*/
}
以下为调用类(以下称B):
package com.sily;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
GenericClassA<Double> c = new GenericClassA<Double>();
String s = c.p(23125.9);
Double j = c.p(23125.34);
GenericClassA<String> e = new GenericClassA<String>();
String ddd = e.d();
GenericClassA<String> d = new GenericClassA<String>();
d.p(34.23);
}
}
会编译出错,是因为c.p(23125.9);这个方法返回的类型与定义的泛型不一致,但泛型类中的T t = (T) (new Double(23));只是警告.但可正常运行。
Double j = c.p(23125.34);这句可正常运行.
但是,String ddd = e.d();这句编译没问题,但运行时会出错,因为e.d()方法实际返回的是一个Double型,如果转换为String肯定出错了,如果改成:
Double ddd = e.d();编译时出错,因为编译器期望的返回类型是String,赋值给String型肯定编译通不过
另外,还有一点,一般都只是A类定义时用到<T>,而B类只是调用,所以是具体的类型,如<String>,<Double>
所以说,泛型出现的目的只是为了限制调用类B调用A时参数类型不出错的一种方式。
示例分析
对于调用类B中GenericClassA a=new GenericClassA ();也可看作是当Object处理,但与GenericClassA<Object> b = new GenericClassA<Object>();不同,如后者b.p(new Object())不会警告,但前者a.p(new Object())会警告,a的所有以泛型作参数的方法都会警告,这也是为了与1.4版本保持向下兼容
GenericClassA<String >不能强制转换为 GenericClassA<Object>
即:
GenericClassA<Object> c = new GenericClassA<String>();
会出错
但
GenericClassA a = new GenericClassA();
GenericClassA<String> c = new GenericClassA<String>();
a=c;
不会出错,这也是为了与1.4版本保持向下兼容;
GenericClassA<?> a ;
GenericClassA<String> c = new GenericClassA<String>();
a=c;
也不会出错
new GenericClassA<?>()不能实例化,因为类型不确定,调用它的相关方法如a.p("ddd")也会出错,因为类型不确定,但可调用其它方法如a.toString();另外,GenericClassA<?>与GenericClassA<? extends Object>一样
再看下面的代码:
GenericClassA<String> c = new GenericClassA<String>();
Double dd = (Double)c.d();
会出错,因为对于编译器来说,c.d();返回的就是String类型,但在GenericClassA中,
该方法如下:
public T d() {
T t = (T) (new Double(23));
return t;
}
所以编译时出错,因为不能编译,所以不能运行(应该是可运行的)
所以以下代码是正确的
GenericClassA<Object> c = new GenericClassA<Object>();
Double dd = (Double)c.d();
实际上是对返回值作了强制类型转换
另外,在java程序类的一个方法中,如p(Object c),则c可有"aaa"等来作参数,则会自动转换为Object ,但在泛型中<Object>是不能自动转换的,即GenericClassA<Object> c = new GenericClassA<String>();会出错
GenericClassA<?> c = new GenericClassA<String>();
c.p("abc");会出错
因为对编译器来说c是一个未知类型(可能是Object及其子类)的GenericClassA,有可能是Double的GenericClassA,所以如果p("abc")会出错
补充:
另外,Eclipse3.1已经对java5提供的支持,大家可在Eclipse3.1中调试以上代码
小结:
以上为对java5的新特征——泛型的一点小小的见解,更详细的内容请参考sun的tutorial:
泛型只是java5的新特征之一,其它特征如变参,元数据,静态导入,增强循环等会在以后陆续介绍,敬请关注
补充(2005-12-14):
1.如果在spring的getHibernateTemplate().find(sql)返回的类型为List<?>(因为类型不确定),那么在多的UnitDAO的getUnitByName()方法中应该返回List<UnitDTO>,这个问题怎么解决?
参考资料:
作者简介:
施祖阳,网名sylilzy,1979年生。
2002年起从事软件开发工作,主要研究JAVA、Linux及相关技术。