站内搜索: 请输入搜索关键词

当前页面: 开发资料首页Java 专题Generics Types 泛型学习笔记<二>

Generics Types 泛型学习笔记<二>

摘要: Generics Types 泛型学习笔记<二>

首先我要特别感谢Schlemiel,他指出了类型协变的问题。其实我以前也看到过gigix翻译的那篇文,但是没看懂也没经大脑。经Schlemiel一提醒,我才意识到,这是泛型的规范。再翻出来看,如醍醐灌顶,真良师益友也。
我写文章的目的,就是为了能够找到更多同好进行交流。没有交流,没有氛围,绝对不会有提高。谢谢Schlemiel,每次读他的文章或评论,都能受到很大的启发。
如果需要深入了解泛型,请阅读程序员杂志2003第7期,或
http://gigix.cool2u.net/download/Variance_in_Java.pdf
ok,继续上次的学习笔记。这篇22页的文章正好读了3天。每天从地铁东四十条到西直门,每次读7页。如果哪位晚上6:30-7:00间看到地铁上有个人拿着本电脑书在读,不妨上来问问是不是俺 ^___^||
另:后面文中每章出现了不少重点,我就按照和文中章节一样的标题。Notes则自己编号。
这次特地把字体变为14px,不知道各位看起来如何啊?会不会太大?
5 泛型方法(函数)
根据上一条,既然通配符类型是只读的,那么怎样才能在函数中写入呢?这就引入了泛型函数(Generic Mehtods):
static void fromArrayToCollection(T[] a, Collection c) {
for (T o : a){
c.add(o); //correct } }
Collection co = new ArrayList;
Collection cs = new ArrayList;
fromArrayToCollection(new Integer[100], co); //correct
fromArrayToCollection(new Number[100], cs); // error
可以知道,不需要传递世纪参数到泛型方法,编译器会自行推断类型。 那么,什么时候使用泛型方法,什么时候使用通配符类型呢?可以这样理解:
Note 5: 可以采用泛型方法来保证读写操作的类型安全。泛型方法相当于原来的多态方法,它的效果是允许执行时选用不同的参数类型,而通配符方法相当于接受Object的方法。
原文:This tells us that the type argument is being used for polymorphism; its only effect is to allow a variety of actual argument types to be used at different invocation sites.
考虑下面的方法,
public static void copy (
List dest, List src) ();
public static void copy (
List dest, List <? extends T> src) ();
哪一个更清楚明了一点?因为S只用了一次,因此可以用通配符类型取代S。这样更简练。通配符类型的另一个好处是,他们可以用在方法外面,作为值域(fields)、本地变量(local variables)或数组的类型。如
static List> history
= new ArrayList>();
public void drawAll(List<? extends Shape> shapes){
history.addLast(shapes); }
说实话,我看到上面的变量定义简直想骂人。这个是定义了一个List的List,也就是history是保存List<? extends Shape>的List。
6 泛型与旧代码
在泛型代码中使用旧代码可能导致类型安全隐患。
public interface Inventory {
void setCats(Collection c);
Collection getCats(); }
Collection c = new ArrayList();
c.add(new BlackCat());
Inventory.setCats(c);
Collection k = Inventory.getCats();
Note 6: 一般编译器无法知道Collection引用了何种类型,这样的没有带有类型的Collection称为row type。这样的类型表示一些未知类型,相当于Collection<?>。
原文:The compiler has no way of knowing what kind of collection the type Collection refers to. It’s called a raw type. It’s more accurate to say that the type Collection denotes a collection of some unknown type like Collection<?>.
这种情况下,把Collection<?>赋值给Collection是合法的,但是会出现一个unchecked warning,未检查警告。表示编译器无法保证它的正确性。因此使用旧代码时候请注意unchecked warning.
Note 7: 泛型编译时会被编译器进行一次称为erasure的过程。可以认为就是将泛型的代码转换为非泛型版本。最终的结果是:JVM不会检查类型安全和完整性,就算出现了unchecked warning也一样。Erasure会删除所有的泛型信息,如将List转换为List,所有的类型变量被替换为最上限的,如Object。并且不管结果代码如何,都会增加类型转换。
原文:Generics are implemented by the Java compilers as a front-end conversion called ensure. It just like a source-to-source translation. As a result, the type safety and integrity of the JVM are never at risk, even in presence of unchecked warnings. Erasure throws out all type information between angle brackets. For example, List is converted into List. All remaining uses of type variables are replaced by the upper bound type variable (usually Object). And, whenever the resulting code isn’t type-correct, a cast to the appropriate type is inserted.
在旧代码中使用泛型代码。与上面情况类似,会出现unchecked warning.
7 Fine Print 美好蓝图?(搞不懂作者的意图)
泛型类被所有的它的子类共享。
List l1 = new ArrayList();
List l2 = new ArrayList();
assert(l1.getClass()==l2.getClass()); // return true
Note 8: 所有的泛型类拥有相同的runtime类(其实从上面一条可以知道),并且,静态变量和方法也会在类的实例间共享。这就是为何在静态方法、变量或初始化中引用类型参数是非法的。
原文:All instances of generics class have the same run-time class. As consequence, the static variables and methods of a class are also shared among all the instances. That’s why it is illegal to refer to the type parameters of a type declaration in a static method or initializer, or in the declaration or initializer of a static variable.
另一个隐含的事实,是无法判断一个类是否instanceof 其泛型类。或类型转换一个对象到一个泛型类型。
Collection cs = new ArrayList;
if (cs instanceof Collection) {} //非法
(Collection) cs; // unchecked warning
T badCast(T t, Object o) {return (T)o};// unchecked warning
Note 9: 类型变量在运行时不存在!这意味着泛型不会占用时间或空间的性能,但不幸的是,你不能可靠的使用类型转换。 原文:type variables don’t exist at run time. This means that they entail no performance overhead in either time nor space. It also means that you can’t reliably use them in casts.
数组可能无法成为一个参数类型。除非是一个通配符类型。
List [] lsa = new List[10]; // 不允许
= new List<?>[10]; // 允许
Object o = isa;
Object[] oa = (Object[])o;
oa[1] = new ArrayList();
String s = lsa[1].get(); //允许的情况下,runtime error
可以声明类型变量的数组,但是不能初始化(new)建立一个新数组。如new T[100],因为类型变量运行时并不存在。
词汇表:
参数类型:parameterized type,形如:new ArrayList<?>,new ArrayList
类型变量:type variable,形如: T getCollection()…
通配符类型:wildcard type,形如:new ArrayList<?>
有界通配符类型:bounded wildcard type,形如:new ArrayList<? extends Object>
原生类型:raw type,指在泛型代码中使用Collection, ArrayList等旧形式
未检查警告:unchecked warning,Java1.5代码安全警告。
To be continue ...
版权声明:
本文由冰云完成,首发于CSDN,作者保留中文版权。
未经许可,不得使用于任何商业用途。
欢迎转载,但请保持文章及版权声明完整。
如需联络请发邮件:icecloud(AT)sina.com
作者相关文章: 用PicoContainer和Nanning实现事务管理(原作) 泛型(Generics Types)学习笔记<一>(原作) 介绍 IoC(原作)
对该文的评论 人气:148 Schlemiel(2004-2-26 8:40:32)
我现在要验证另一个问题:具体类能不能继承泛型类?也就是说(我用书名号代替尖括号了,不然又要被转码): public class IntegerList extends ArrayList《Integer》 { 这段代码是否正确?如果正确,IntegerList类是否具有泛型类的那种类型检查能力?
然后,再一个有趣的想法: pulic class GenericClass《class T》 extends T { 这段代码又是否正确?如果这两个想法都成立,我们倒是可以用泛型Java做出些很有意思的OO设计。
举个例子:所有的DAO(Data Access Object)通常都提供CRUD方法,为了强类型检查,我们通常会为每个实体类提供一个DAO,譬如: public interface UserDAO extends IDAO { public User create(); public User load(Serializable id); public User update(User entity); public void delete(User entity); } 对于另一个DAO(譬如ArticleDAO),方法也差不多,只不过参数和返回值的类型不同。用泛型方法,我们就可以做出一个通用并且有强类型检查的DAO类。
icecloud(2004-2-26 1:33:58)
我晕……
guozhenjie(2004-2-25 22:47:44)
默默,是我啊!我给你顶!!!
eggs112(2004-2-25 17:48:36)
刚学JAVA,不只说了些什么。
icecloud(2004-2-25 17:21:38)
Java这样做确实很令人不爽。希望有jvm能够从底层实现一下generic试试看
ripper(2004-2-25 16:27:01)
Java的范型实现来自于一个叫做Pizza的项目。后来呢改名叫做GJ,再后来通过JSR被融合进Java语言。由于Java的范型实现中有一个重要的设计目标,即使范型实现能够运行于现有的、未经修改的JVM上。不修改JVM当然看上去很美,但也会带来一大堆稀奇古怪的限制。
Java的范型中,得不到一般范型实现所能获得的执行效率上的提高。原因在于Java中的范型类在编译时,编译器会将类型参数替换回object。为了讨JVM的欢心,编译器自动加入了你并没有写过的类型转换操作。因此你得到的仅仅是语法上的甜头,而没有获得执行效率的提高。这是一个问题。
第二个问题,也是更严重的问题是,Java的范型实现在运行时偷换了编译时的实际类型,当你对一个范型的List使用反射功能时,你可不知道这个List是个什么类型的List。由于失去了类型信息,动态代码生成功能和反射功能都没法使用。
另外,多谢gigix的翻译: http://gigix.cool2u.net/download/Variance_in_Java.pdf
下面引用一段,印证印证。 ================== 4.类型协变的实现 ... 这个扩展与JSR-14所提出的泛型扩展紧密结合在一起,并且具有后者的大多数优点和局限。 扩展后的编译器仍然兼容旧的代码,输出的字节码可以在不经修改的JVM平台上运行。静 态安全的数组类型允许创建泛型类的数组,从而消除了泛型Java的一个大问题,但“缺乏 运行时类型信息”的问题仍然存在。
后记: 唉,java这样发展不行呀,走自己的路怕是走不通,还是一门心思静下心来励精图治悬梁刺股兢兢业业踏踏实实抄.net算了。 你看1.5里面的抄attribute,抄boxing/unboxing,抄enum...抄得多好,偏偏要用自己的法子实现generic。 唉,不知道是怎么想的,熟悉Java的老大能不能说说其中的原因啊?
↑返回目录
前一篇: Generics Types 泛型学习笔记<三>
后一篇: GENERATING INTEGER RANDOM NUMBERS