Effective Java笔记(29)优先考虑泛型

这篇具有很好参考价值的文章主要介绍了Effective Java笔记(29)优先考虑泛型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        一般来说 ,将集合声 明参数化,以及使用 JDK 所提供的泛型方法,这些都不太困难 。编写自己的泛型会比较困难一些,但是值得花些时间去学习如何编写 。

        以简单的(玩具)堆校实现为例 :

// Object -based collection - a prime candidate for generics
public class Stack
{
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(0bject e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public object pop() {
        if (size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null; // Eliminate obsolete reference
        return result;
    }
    public boolean isEmpty () {
        return size == 0;
    }
    private void ensureCapacity () {
        if (elements.length == size)
            elements = Arrays.copyOf(elements, 2 * size + 1);
    }
}

        这个类应该先被参数化,但是它没有,我们可以在后面将它泛型化( generify ) 。 换句话说,可以将它参数化,而又不破坏原来非参数化版本的客户端代码 。 也就是说,客户端必须转换从堆楼里弹出的对象,以及可能在运行时失败的那些转换 。 将类泛型化的第一步是在它的声明中添加一个或者多个类型参数 。 在这个例子中有一个类型参数,它表示堆桔的元素类型,这个参数的名称通常为 E 。

        下一步是用相应的类型参数替换所有的 Object 类型,然后试着编译最终的程序:

public class Stack<E> {
    private E[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;
    public Stack() {
        elements = new E[DEFAULT_INITIAL_CAPACITY] ;
    }
    public void push(E e) {
        ensureCapacity();
        elements[size++] = e;
    }
    public E pop( {
        if (size == 0)
            throw new EmptyStackException();
        E result = elements[--size];
        elements[size] = null; // Eliminate obsolete reference
        return result;
    }
    ...// no changes in isEmpty or ensureCapacity
}

        通常,你将至少得到 一个错误提示或警告,这个类也不例外 。 幸运的是,这个类只产生一个错误,内容如下:

Effective Java笔记(29)优先考虑泛型,Effective Java,java,开发语言,后端

        你不能创建不可具体化的( non-reifiable )类型的数组,如 E 。 每当编写用数组支持的泛型时,都会出现这个问题 。 解决这个问题有两种方法 。 第一种,直接绕过创建泛型数组的禁令 : 创建一个 Object 的数组,并将它转换成泛型数组类型 。 现在错误是消除了,但是编译器会产生一条警告 。 这种用法是合法的,但(整体上而言)不是类型安全的:

Effective Java笔记(29)优先考虑泛型,Effective Java,java,开发语言,后端

        编译器不可能证明你的程序是类型安全的,但是你可以 。 你自己必须确保未受检的转换不会危及程序的类型安全性 。 相关的数组(即 elements 变量)保存在一个私有的域中,永远不会被返回到客户端,或者传给任何其他方法 。 这个数组中保存的唯一元素,是传给push 方法的那些元素,它们的类型为 E ,因此未受检的转换不会有任何危害 。 

        一旦你证明了未受检的转换是安全的,就要在尽可能小的 范围中禁止警告 。 在这种情况下,构造器只包含未受检的数组创建,因此可以在整个构造器中禁止这条警告 。 通过增加一条注解   @SuppressWarnings 来完成禁止,Stack 能够正确无误地进行编译,你就可以使用它了,无须显式的转换,也无须担心会出现 ClassCastException 异常:

@SuppressWarnings ("unchecked")
public Stack() {
    elements = (E[]) new Object [DEFAULT_INITIAL_CAPACITY];
}

         消除 Stack 中泛型数组创建错误的第 二种方法是,将 elements 域的类型从 E []改为 Object[] 。 这么做会得到一条不同的错误:

Effective Java笔记(29)优先考虑泛型,Effective Java,java,开发语言,后端

         通过把从数组中获取到的元素由 Object 转换成 E ,可以将这条错误变成一条警告:

Effective Java笔记(29)优先考虑泛型,Effective Java,java,开发语言,后端

        由于 E 是一个不可具体化的( non -reifiable )类型,编译器无法在运行时检验转换 。 你还是可以自己证实未受检的转换是安全的,因此可以禁止该警告 。 我们只要在包含未受检转换的任务上禁止警告,而不是在整个 pop 方法上禁止就可以了,方法如下:

public E pop() {
    if(size==0)
        throw new EmptyStackException();
    // push requires elements to be of type E, so cast is correct
    @SuppressWarnings ("unchecked") E result =
        (E) elements[--size];
    elements[size] = null; // Eliminate obsolete reference
    return result;
}

        这两种消除泛型数组创建的方法,各有所长 。 第一种方法的可读性更强 : 数组被声明为 E []类型清楚地表明它只包含 E 实例 。 它也更加简洁 : 在一个典型的泛型类 中,可以 在代码中的多个地方读取到该数组;第一种方法只需要转换一次(创建数组的时候),而第二种方法则是每次读取一个数组元素时都需要转换一次 。 因此,第一种方法优先,在实践中也更常用 。 但是,它会导致堆污染( heap pollution ),详见第 32 条 : 数组的运行时类型与它 的编译时类型不匹配(除非 E 正好是 Object ) 。 这使得有些程序员会觉得很不舒服,因而选择第二种方案,虽然堆污染在这种情况下并没有什么危害 。

        下面的程序示范了泛型 Stack 类的使用方法 。 程序以倒序的方式打印出它的命令行参数,并转换成大写字母 。 如果要在从堆战中弹出的元素上调用 String 的 toUpperCase方法,并不需要显式的转换,并且确保自动生成的转换会成功:

public static void main(String[] args) {
    Stack<String> stack = new Stack<>();
    for (String arg : args)
        stack.push(arg);
    while (!stack.isEmpty())
        System.out.println(stack.pop().toUpperCase();
}

        看来上述的示例与第 28 条相矛盾了,第 28 条鼓励优先使用列表而非数组 。 实际上不可能总是或者总想在泛型中使用列表 。Java 并不是生来就支持列表,因此有些泛型如 ArrayList,必须在数组上实现 。 为了提升性能,其他泛型如 HashMap 也在数组上实现 。

        总而言之,使用泛型比使用需要在客户端代码中进行转换的类型来得更加安全,也更加容易。 在设计新类型的时候,要确保它们不需要这种转换就可以使用 。 这通常意味着要把类做成是泛型的。 只要时间允许,就把现有的类型都泛型化 。 这对于这些类型的新用户来说会变得更加轻松,又不会破坏现有的客户端 。文章来源地址https://www.toymoban.com/news/detail-638872.html

到了这里,关于Effective Java笔记(29)优先考虑泛型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Effective Java笔记(11)覆盖 equals 时总要覆盖 hashCode

             在每个 覆盖了 equals 方法的类中,都 必须 覆盖 hashCode 方法 。 如果不这样做的话,就会违反 hashCode 的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这类集合包括 HashMap 和 HashSet 。 下面是约定的内容,摘自 Object 规范: 1、在应用程序的执

    2024年02月15日
    浏览(57)
  • Effective Java笔记(3)用私有构造器或者枚举类型强化 Singleton 属性

            Singleton 是指仅仅被实例化一次的类 。Singleton 通常被用来代表一个无状态的对象,如函数,或者那些本质上唯一的系统组件 。 使类成为 Singleton会使它的害户端测试变得十分困难 ,因为不可能给 Singleton 替换模拟实现,除非实现一个充当其类型的接口 。      

    2024年02月15日
    浏览(51)
  • Effective Java笔记(9)try-with-resources 优先于 try -finally

            Java 类库中包括许多必须通过调用 close 方法来手工关闭的资源 。 例如 InputStream 、OutputStream 和 java.sql.Connection 。 客户端经常会忽略资源 的关闭 ,造成严重的性能后果也就可想而知了 。 虽然这其中的许多资源都是用终结方法作为安全网,但是效果并不理想。  

    2024年02月15日
    浏览(53)
  • Java笔记(集合、散列表、Map、泛型)

    set:无序不可重复 无序:不保证有序,就是有可能有序,有可能无序 不可重复:不能添加重复数据 HashSet TreeSet:底层是红黑树,会自动排序,意味着里面存储的必须是同类型的元素对象 数字:从小到大排序 字符串:一次比较每一位的ascll码值 日期:自然日期顺序 1.1.TreeS

    2024年02月19日
    浏览(43)
  • Effective Java笔记(16)要在公有类而非公有域中使用访问方法

            有时候,可能需要编写一些退化类,它们没有什么作用,只是用来集中实例域 :         由于这种类的数据域是可以被直接访问的,这些类没有提供 封装 ( encapsulation )的功能。 如果不改变 API,就无法改变它的数据表示法, 也无法强加任何约束条件;当域

    2024年02月16日
    浏览(42)
  • Effective第三版 中英 | 第2章 创建和销毁对象 | 当面临多个参数的构造器时考虑使用构建器

    大家好,这里是 Rocky 编程日记 ,喜欢后端架构及中间件源码,目前正在阅读 effective-java 书籍。同时也把自己学习该书时的笔记,代码分享出来,供大家学习交流,如若笔记中有不对的地方,那一定是当时我的理解还不够,希望你能及时提出。如果对于该笔记存在很多疑惑,

    2024年02月07日
    浏览(45)
  • 《Effective Java》如果说我需要一本Java编程的书,那就是它了

    《Effective Java》是Java编程领域的一本经典之作,由Joshua Bloch撰写,旨在帮助Java程序员提高编码技巧,写出更加健壮、高效和易于维护的代码。 本书以清晰、简洁的风格介绍了Java编程中的最佳实践和常见陷阱。通过深入的解释和实践经验,作者分享了大量有关类设计、方法设

    2024年04月17日
    浏览(41)
  • 《Effective Java》:Java编程圣经,Bloch大师亲授高效优雅编程之道!

    是谁?作品一出版就获得著名的Jolt图书大奖,每一版本豆瓣评分均超9.0! 连Java之父James Gosling都多次表白他的作品“我很希望我10年前就能拥有这本书。有人可能认为我不需要任何Java方面的书籍,但是我需要这本书”,还在 JavaOne 2001 上直呼“去买这本书吧!”。 他就是《

    2024年04月09日
    浏览(41)
  • 【粉丝福利社】《Effective Java》(文末送书-完结)

    🏆 作者简介,愚公搬代码 🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等

    2024年04月17日
    浏览(46)
  • 《Effective Java》第三条 用私有构造器或者枚举类型强化Singleton属性

    Singleton其实就是单例,即一个类在一个应用程序中只被实例化一次,只有一个对象。 本节讨论三种实现方式 私有构造+共有成员 私有构造+静态工厂方法+私有成员 枚举实现 1、共有成员 构造方法私有,有一个该类类型的公有不可变的实例域。 1.1 code 当类加载的时候就会创建

    2024年02月16日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包