zoukankan      html  css  js  c++  java
  • [置顶] 学习JDK源码:可进一步优化的代码

    1、参数化类型的构造函数比较啰嗦

    • new HashMap<String, List<String>>()

    如果你调用参数化类的构造函数,那么很不幸,你必须要指定类型参数,即便上下文中已明确了类型参数。这通常要求你连续两次提供类型参数:

        Map<String, List<String>> m = new HashMap<String, List<String>>();  


    假设HashMap提供了如下静态工厂

        public static <K, V> HashMap<K, V> newInstance(){  
            return new HashMap<K, V>();  
        }  


    然后你就可以讲上文冗长的声明替换为如下这种简洁的形式:

    Map<String, List<String>> m = HashMap.newInstance(); 


    ——com.google.common.collect.Lists则解决了这个问题:

    List<String> l = Lists.newArrayList();

    2、违反“避免创建不必要的对象”

    • Boolean(String)

    Boolean(String)有点多余,因为已经有静态工厂方法:Boolean.valueOf(String)。

    它几乎总是比构造函数Boolean(String)更可取。构造函数每次被调用时都会创建一个新对象,而静态工厂方法则从来不要求这样做,实际上也不会这么做。


    3、避免使用finalize

    • FileInputStream.finalize()

    要避免用finalize来释放资源,而应该提供一个显式的终止方法。例如FileInputStream.close();


    finalizer的作用之一是,可以充当“安全网”,以防对象所有者忘记调用显式的终止方法。虽然不能保证finalizer会被及时调用,但当客户端没有调用显式终止方法时,迟一点释放资源总比不释放好。不过如果finalizer发现有未被终止的资源,则必须打印一条警告,表明客户端代码有bug,需要修复。

    有四个类(FileInputStream、FileOutputStream、Timer、Connection)使用了finalizer作为安全网,以防显式终止方法未被调用。不幸的是,这些finalizer都没有打印警告。当API发布后,这种警告一般就不能添加到API了,因为可能破坏已有的客户端代码。

       protected void finalize() throws IOException {
        if (fd != null) {
            if (fd != fd.in) {
            close();
            }
        }
        }

    4、equals的实现违反约定

    • URL.equals()

    java.net.URL的equals方法依赖于对URL中主机的IP地址的比较,而将主机名转译成IP地址需要访问网络,随着时间推移,并不保证能范围相同的结果。——违反一致性。这就会导致URL的equals方法违反约定,并且已经在实践中引起问题了。

    不幸的是,由于兼容性需求,这一行为无法改变。除了少数例外情况,equals方法必须对驻留在内存中的对象进行确定性计算。


    • Timestamp.euals()

    ava.sql.Timestamp扩展了java.util.Date类并增加了nanoseconds域。Timestamp的equals方法就违反了对称性,如果Timestamp和Date被用于同一个集合中,或以其他什么方式混在一起使用,则会引起错误的行为。

    ——无法在扩展可实例化类的时候,增加一个值组件,同时又保证equals约定


    Timestamp有一个免责声明,提醒程序员不要混用Date和Timestamp。虽然只要不混用他们就不会有麻烦,但是谁都不能阻止你混用他们,而结果导致的错误将会很难调试。Timestamp的这种行为是个错误,不值得效仿。

             /** 
             * Note: This method is not symmetric with respect to the  
             * <code>equals(Object)</code> method in the base class. 
             */  
           public boolean equals(java.lang.Object ts) {  
              if (ts instanceof Timestamp) {  
            return this.equals((Timestamp)ts);  
              } else {  
            return false;  
              }  
            }  

    5、接口设计问题

    • Cloneable接口

    Cloneable接口的目的是作为对象的一个mixin接口,表明对象允许克隆;但这个目的没有达到。

    其主要缺点是,Cloneable缺少一个clone()方法,而Object.clone()是受保护的。


    通常,实现接口是为了表明类可以为它的客户做些什么;而Cloneable却是改变了超类中受保护方法的行为。

    ——区别java.rmi.Remote接口,其中也不具有任何方法,它是一个记号接口

    6、compareTo与equals不一致

    • BigDecimal.compareTo

        compareTo方法的等同性测试必须与equals方法的结果相同。如果遵守了这一条,则称compareTo方法所施加的顺序与equals一致;反之则称为与equals不一致当然与equals不一致的compareTo方法仍然是可以工作的,但是,如果一个有序集合包含了该类的元素,则这个集合可能就不能遵守相应集合接口(Collection、Set、Map)的通用约定。这是因为这些接口的通用约定是基于equals方法的,但是有序集合却使用了compareTo而非equals来执行等同性测试。尽管出现这种情况并不会造成灾难性后果,但是应该注意这种情况。

        【例】例如BigDecimal类的compareTo方法与equals不一致。如果创建一个HashSet实例,并添加两个元素new BigDecimal("1.0")和new BigDecimal("1.00"),则集合会包含两个元素,因为这两个实例通过equals检测并不相等;然而,如果使用TreeSet而非HashSet,则集合中会只包含一个元素,因为这两个实例通过compareTo检测是相等的。

    7、public类不应暴露其内部字段

    如果一个类可以被包外访问,那么就要提供访问方法,以便可以灵活地改变类的内部表示。如果public类暴露了其数据域,则要想在将来改变内部表示是不可能的

    • Point

    public class Point extends Point2D implements java.io.Serializable {
    
        public int x;
    
        public int y;
    • Dimension

    public class Dimension extends Dimension2D implements java.io.Serializable {
        
        public int width;
    
        public int height;










    其他

    唯一声称保证finalizer()会被执行的方法是System.runFinalizersOnExit,以及Runtime.runFinalizersOnExit。——但这两个方法都有致命缺陷并且都已弃用。



    未完待续。。。

  • 相关阅读:
    Redis 字符串(String)
    Redis 哈希(Hash)
    Redis 键(key)
    Redis 命令
    Redis 数据类型
    Redis 配置
    Log4j 2X 日志文件路径问题
    shiro项目从 log4j1X 迁移到 log4j2X
    shiro+SpringMVC 项目 配置404页面
    邮件发送-》http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3221884.html
Copyright © 2011-2022 走看看