`

优先考虑泛型

 
阅读更多

        看如下一个泛型的例子:

 

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. // Initial attempt to generify Stack = won't compile!  
  2. public class Stack<E> {  
  3.     private E[] elements;  
  4.     private int size = 0;  
  5.     private static final int DEFAULT_INITIAL_CAPACITY = 16;  
  6.       
  7.     public Stack() {  
  8.         elements = new E[DEFAULT_INITIAL_CAPACITY];  
  9.     }  
  10.   
  11.     public void push(E e) {  
  12.         ensureCapacity();  
  13.         elements[size++] = e;  
  14.     }  
  15.   
  16.     public E pop() {  
  17.         if (size == 0)  
  18.             throw new EmptyStackException();  
  19.         E result = elements[--size];  
  20.         elements[size] = null;  
  21.         return result;  
  22.     }  
  23.       
  24.     public boolean isEmpty() {  
  25.         return size == 0;  
  26.     }  
  27.       
  28.     private void ensureCapacity() {  
  29.         if (elements.length == size)  
  30.             elements = Arrays.copyOf(elements, 2 * size + 1);  
  31.     }  
  32. }  

        上面这个泛型栈的例子会存在一个错误,25条说过,E是不可具化的,而数组是可具化的,所以不能用E来使用诸如new E[]这样的数组申请方法,为了解决这个问题,我们可以将new E[]改为new Object[]。至此,又得到了一条警告信息,因为我们要把Object型的数组赋给E型,因为编译器无法确定E的具体类型,所以警告这是不是类型安全的。但是由于elements只有在push中使用,且压进的是E型元素,所以我们可以判断出这是安全的,因此加上强制类型转换(E())new Object[...],这是解决上面错误问题的每一种方法。但是必须确保未受检的转换不会危及到程序的类型安全,相关的数组保存在一个私有域中,永远不会被返回到客户端去,或者传递给任何方法,也就是说存在不稳定的因素,但是是完成在服务端可控的。一旦证明了未受检转换是安全的,就要在尽可能小的范围内禁止警告,在这种情况下,构造器只包含未受检的数组创建,因此可以在整个构造器中禁止这条警告。

 

        消除错误的第二种方法是直接把elements声名为Object类型的,但是,这又会在

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. E result = elements[--size];  

        引入一条错误,同样的,我们可以加入强制类型转换来解决这个问题

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. E result = (E)elements[--size];  

        与第一种情况类似。这也会得到一条警告,同样的,也可证明这种情况下是安全的,所以可以禁止该警告。依据最小化原则,应该直接在此名上加注释来禁止警告。

 

        这两种方法,一般来说禁止数组类型的未受检转换比禁止标题类型更危险,所以建议使用第二种方法。但是在比这个例子更实际的泛型中,或许代码中会有多个地方需要从数组中读取元素,因此第一种方法比第二种方法开销更小一些,这也是第一种方法更常用的原因。这个例子看起来违反了25条(它告诉我们对于泛型列表要优于数组),实际上因为JAVA并不是生来就支持列表,所以有些泛型如ArrayList必须使用数组来实现,有的时候为了提升性能,也会考虑用数组来实现,比如HashMap。

        有一些泛型限制了可允许的类型参数值。例如

[java] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. class DelayQueue<E extends Delayed> implements BlockingQueue<E>;  

        类型参数列表要求实际的类型参数E必须是java,util.concurrent.Delayed的一个子类型,它允许DelayQueue实现及其客户端在DelayQueue元素上利用Delayed方法,无需显示的转换,注意,第一个类型都是自身的子类型,因此创建DelayQueue<Delayed>是合法的。

 

        总之,使用泛型比使用需要在客户端代码中进行转化的类型来的更安全。也更容易,在设计新类的时候,要确保它们不需要这种转换就可以使用。这通常意味着要把类做成是泛型的。

分享到:
评论

相关推荐

    习----题-Java-Web程序设计教程-[共2页].pdf

    但要依据存储要求不同(如读优先还是写优先)选择适合的集合类 型。此外,本章还介绍了 Java 泛型编程。限于篇幅,我们没有详细研究泛型编程技术。如果要深 入了解泛型编程,请查阅相关资料。 习 题 上机实践 1.将...

    typed-panels:Typed Panels是一个完全以TypeScript编写的布局和功能优先的javascript框架

    您应该考虑使用此框架: 创建(丰富)Web应用程序考虑或开始使用 需要一致的用户界面希望少担心UI的可维护性,并希望在尽可能短的时间内构建它想念您使用服务器端语言使用的LINQ(或其他DSL用于对象)和泛型,...

    swift-words:快速翻译

    原则如果已经有广泛使用的术语,优先考虑(×属性/◯属性,×模式匹配/◯模式匹配)尽量翻译成日文(×存物/◯存物)如果您无论如何都无法翻译成日语,请尽可能使用片假名,除了关键字代码(×模式/◯模式)转换为...

    react-proptypes-to-typescript:将react原型转换为typescript

    可移除属性类型和转换至类型脚本,优先考虑转换后代码的兼容性,减少手动修正的代码量,以实现快速迁移。特征: 代理PropTypes到React.Component泛型类型及排除PropTypes 根据初始状态, setState()调用以及this....

    javalruleetcode-leetcode:leetcode刷题集合

    java lru leetcode README leetcode题目分类 1.数组 2.Linked List (注意如果是两个Integer类型进行比较要用equals,有赞笔试真题,要学会在原地解决这个...9.深度优先搜索和广度优先搜索 每日一题 10.贪心算法 11.

    bootstrap-4.0.0-beta.2.zip

    Bootstrap 是全球最受欢迎的前端组件库,用于开发响应式布局、移动设备优先的 WEB 项目。 Bootstrap 是一套用于 HTML、CSS 和 JS 开发的开源工具集。利用我们提供的 Sass 变量和大量 mixin、响应式栅格系统、可扩展...

    突破程序员基本功的16课.part2

    4.4.8 考虑使用SoftReference 4.5 小结 第5课 表达式中的陷阱 5.1 关于字符串的陷阱 5.1.1 JVM对字符串的处理 5.1.2 不可变的字符串 5.1.3 字符串比较 5.2 表达式类型的陷阱 5.2.1 表达式类型的自动提升 ...

Global site tag (gtag.js) - Google Analytics