Java5 增加的泛型语法,使类型模板的应用得到了提升,但它的运行期擦拭的做法(为向前兼容),令人诟病,
使得一个Map集合,通过反射拿到的集合元素的泛型类型,不是实际使用类型,而是K和V(字节码编译期保留)。
另一个有争议的地方是:
泛型违反了里氏代换原则(Liskov's Substitution Principle),即:子类应该在任何地方都能替换父类。
假设一个函数:
void xxx(List<Object> list);
调用:
List<String> list = ...
xxx(list); // 编译出错
当然,你可以使用下面的变通方式就不会出错:
void xxx(List<? extends Object> list);
主要的问题在于:List<String> 是不是 List<Object> 的子类?
我觉得应该是,至少“人”认为是,面象对象的主要目的是什么?就是让人理解程序,而不是机器。
而官方给出的答案却是:List<String> 不是 List<Object> 的子类
Java泛型规格说明书 写道
让我们测试一下我们对泛型的理解。下面的代码片断合法么?
List<String> ls = new ArrayList<String>(); //1
List<Object> lo = ls; //2
第1行当然合法,但是这个问题的狡猾之处在于第2行。
这产生一个问题:
一个String的List是一个Object的List么?大多数人的直觉是回答:“当然!”。
好,在看下面的几行:
lo.add(new Object()); // 3
String s = ls.get(0); // 4: 试图把Object赋值给String
这里,我们使用lo指向ls。我们通过lo来访问ls,一个String的list。我们可以插入任意对象进去。结果是ls中保存的不再是String。当我们试图从中取出元素的时候,会得到意外的结果。
java编译器当然会阻止这种情况的发生。第2行会导致一个编译错误。
总之,如果Foo是Bar的一个子类型(子类或者子接口),而G是某种泛型声明,那么G<Foo>是G<Bar>的子类型并不成立!!
这可能是你学习泛型中最难理解的部分,因为它和你的直觉相反。
这种直觉的问题在于它假定这个集合不改变。我们的直觉认为这些东西都不可改变。
举例来说,如果一个交通部(DMV)提供一个驾驶员里表给人口普查局,这似乎很合理。我们想,一个List<Driver>是一个List<Person>,假定Driver是Person的子类型。实际上,我们传递的是一个驾驶员注册的拷贝。然而,人口普查局可能往驾驶员list中加入其他人,这破坏了交通部的记录。
为了处理这种情况,考虑一些更灵活的泛型类型很有用。到现在为止我们看到的规则限制比较大。
上面所描述的语义限制根本没有意义,如果想限制用户在List<String>中加入Object, 因为泛型的运行期擦拭,等于白做。
因为想做这个语义上的限制,而牺牲直观的理解非常不值,加一个"?"问号作为替代方案,只会使泛型更复杂,使用也不方便。
用户必须在"?"问号与"Object"间绕来绕去,烦也不烦,或许可以问:"?"问号等于"Object"吗?呵呵,maybe.
分享到:
相关推荐
这是一个使用JAVA实现的泛型编程,分为两部分,第一部分创建泛型类,并实例化泛型对象,得出相加结果。 第二部分用户自行输入0--4,选择要进行的加减乘除运算或退出,再输入要进行运算的两个数,并返回运算结果及...
Java泛型的用法及T.class的获取过程解析 Java泛型是Java编程语言中的一种重要特性,它允许开发者在编写代码时指定类型参数,从而提高代码的灵活性和可读性。本文将详细介绍Java泛型的用法 及T.class的获取过程解析...
Java泛型机制详解 Java泛型是Java语言中的一种机制,用于在编译期检查类型安全。Java泛型的出现解决了Java早期版本中类型安全检查的缺陷。Java泛型的好处是可以在编译期检查类型安全,避免了运行时的...
Java 泛型详解 Java 泛型是 Java SE 5.0 中引入的一项特征,它允许程序员在编译时检查类型安全,从而减少了 runtime 错误的可能性。泛型的主要优点是可以Reusable Code,让程序员编写更加灵活和可维护的代码。 ...
Java泛型是Java编程语言中的一个强大特性,它允许我们在定义类、接口和方法时指定类型参数,从而实现代码的重用和类型安全。在Java泛型应用实例中,我们可以看到泛型如何帮助我们提高代码的灵活性和效率,减少运行时...
1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1.java泛型定义.zip1....
Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...
Java 泛型是Java SE 5.0引入的一...以上就是关于Java泛型方法的基本介绍和使用示例,希望对你有所帮助。如果你想要进一步了解或实践,可以参考提供的`GenericMethod.java`源代码文件,或者查阅`Java.jpg`中的相关图片。
4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip4.java泛型的限制.zip...
Java泛型是Java SE 5.0引入的一个重要特性,它极大地增强了代码的类型安全...在进行"关于Java基础的泛型的练习"时,可以尝试编写不同的泛型类、泛型方法,体验泛型带来的便利,并理解其背后的类型系统和类型擦除机制。
Java 泛型是Java SE 5.0引入的一项重要特性,极大地增强了代码的类型安全性和重用性。泛型接口是泛型在接口中的应用,它允许我们在接口中定义带有类型参数的方法,使得实现该接口的类可以使用不同的数据类型。下面...
综上所述,虽然Java泛型在编译后会进行类型擦除,但通过上述技巧,我们仍然能够在运行时获得关于泛型类实例化类型的一些信息。在实际开发中,这些方法可以帮助我们编写更加灵活和安全的代码。在示例文件`GenericRTTI...
在编程世界中,C#和Java都是广泛应用的高级编程语言,它们都支持泛型这一强大的特性,以提高代码的类型安全性和重用性。本文将深入探讨C#和Java在泛型实现上的异同,帮助开发者更好地理解和利用这两种语言的泛型功能...
因此,泛型在运行时并不存在,所有关于泛型的操作都在编译期间完成。 2. **边界通配符**:在处理泛型时,我们经常遇到边界通配符,如`<? extends T>`和`<? super T>`。前者表示类型参数可以是T或T的任何子类型,后...
"Java 泛型学习" Java 泛型是 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的...