`

优先考虑泛型

 
阅读更多

        看如下一个泛型的例子:

 

[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>是合法的。

 

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

分享到:
评论

相关推荐

    C#泛型集合与非泛型集合

    因此,在C# 2.0 及其后续版本中,强烈建议开发者优先使用泛型集合。这不仅可以提高代码的质量和可维护性,还能有效提升应用程序的性能。在实际开发过程中,合理选择合适的集合类型对构建高效稳定的应用系统至关重要...

    Rules of thumb for the design of C0x 英文

    1. **优先考虑泛型而非特化**:Stroustrup强调,C++0x的设计目标是支持更广泛的编程风格和设计模式,而不仅仅是针对特定情况的解决方案。这意味着模板和泛型编程被赋予了更高的重视,以便开发者能创建灵活且可复用的...

    5本java学习用书

    例如,它涵盖了枚举优于常量、避免使用原始类型、优先考虑泛型、以及何时使用静态工厂方法而非构造函数等主题。 3. **《Thinking in Java》**:Bruce Eckel的这部巨著深入细致地介绍了Java语言,不仅涵盖基础,还...

    Java编码规范实用版

    - 集合使用时,优先考虑泛型,避免类型转换异常。 以上仅为《Java编码规范实用版》中部分关键知识点,实践中还应结合实际项目需求和个人习惯进行调整。通过遵循这些规范,可以写出更加优雅、易于理解和维护的Java...

    泛型的使用

    在需要类似数组功能时,优先考虑使用集合类。 4. **重视编译器警告**:编译器给出的警告信息是为了提示潜在的问题,不应忽视。及时修正警告可以帮助保持代码的健壮性。 **类型擦除**是Java泛型的关键特性,意味着...

    详解C#中的泛型以及编程中使用泛型的优点

    这些类比非泛型的`ArrayList`和`Hashtable`更安全、更高效,应该优先考虑使用。 此外,泛型不仅限于集合类,还可以用于创建泛型方法、泛型委托、泛型事件等。例如,一个泛型方法可能接受一个泛型参数,并根据传入的...

    cpp-微小的C库利用未定义的行为来实现泛型编程

    标题中的“cpp-微小的C库利用未定义的行为来实现泛型编程”指的是一个C语言编写的库,它尝试通过利用...不过,重要的是要记住,虽然这样的技术可能很吸引人,但在实际应用中应优先考虑代码的可读性、稳定性和安全性。

    C++泛型算法的一些总结

    相反,对于关联容器,应优先考虑使用它们特有成员函数,如`insert`、`erase`等。 `remove`和`unique`的泛型版本不直接修改容器,它们只是将不需要的元素移动到容器的末尾,然后返回一个迭代器,用户需要额外处理...

    自己实现vector不使用泛型

    5. **迭代器**:虽然不强制要求,但为了提高可读性和兼容性,可以考虑实现迭代器接口,允许用户通过迭代器遍历`Vector`中的元素。 在`Vector.cpp`和`Vector.h`文件中,`Vector`类的实现可能会包含这些成员函数的...

    支持泛型的省份等(按照热门城市、a-z、# 排序的实体)选择模块

    这通常需要在程序中维护一个动态更新的热门城市列表,并在展示时优先显示。按字母顺序排序(a-z)则是将所有城市按照名称的首字母进行升序排列,这是一种常见且直观的排序方式。至于"#",在编程中通常表示特殊含义,...

    算符优先文法(MFC)

    C++是一种强大的、通用的编程语言,它支持面向对象编程和泛型编程。在C++中实现一个算符优先文法的语法分析器,通常会涉及以下几个关键知识点: 1. **词法分析**:这是编译器的第一步,它将源代码分解成一个个称为...

    深度优先遍历 广度优先遍历 Dijikstta

    在实际编程中,可以使用模板(templates)实现泛型程序,使代码能够处理不同类型的节点和边。 以下是一个简单的C++代码示例,展示了如何实现DFS、BFS和Dijkstra算法: ```cpp #include #include #include #...

    堆排序及优先队列源代码_上机c++ 添加元素 删除最大节点

    - **泛型实现**:通过模板技术实现堆排序及优先队列,使其支持不同类型的数据。 通过以上分析,我们可以看到堆排序及优先队列在实际编程中的应用是非常广泛的,掌握其基本原理及实现方法对于提高编程能力非常有帮助...

    java代码优化笔记

    关于HashMap的遍历,应优先考虑使用entrySet()而不是keySet()进行遍历,这样可以直接访问到值,避免了对键进行查询,提高了效率。局部变量的使用优于成员变量,因为它们通常存储在栈中,访问速度较快。对象重用是...

    c#重写HashTable

    如果可能,优先考虑使用泛型`Dictionary`,它可以提供类型安全和更好的性能。 以上就是关于在C#中重写`HashTable`的相关知识点,包括理解`HashTable`的原理、重写的原因、步骤、注意事项以及泛型替代方案。通过这些...

    effectice_java第二版 英文

    10. **条目10:优先考虑使用枚举而非int常量(Use Enums Instead of Int Constants)** 枚举提供了类型安全,可以方便地添加方法和实现接口,比使用整数常量更易管理和维护。 11. **条目11:使用泛型(Generics)*...

    java除去类里面的黄色警告

    在Java编程中,IDE(如...总之,在处理Java代码中的黄色警告时,开发者应该保持警惕,避免盲目地使用`@SuppressWarnings`注解掩盖问题,而是应该优先考虑修复警告所指示的潜在问题,从而编写出更健壮、更安全的代码。

    c#分页方案

    例如,在数据量较大且ID已有序的情况下,优先考虑分页方案二;而对于复杂查询或需要高度定制化的分页逻辑,则可能需要采用分页方案三。此外,无论采用哪种方案,都应确保关键字段(如ID)上有适当的索引,以提高查询...

    Effecctive java 中文版

    除非必要,否则应优先考虑使用构造器或克隆工厂方法。 以上只是《Effective Java》众多知识点中的一部分,每一条都值得深入理解和实践。通过学习这些最佳实践,Java开发者可以显著提升代码质量,优化程序性能,并...

Global site tag (gtag.js) - Google Analytics