• Effective java -- 1


    写博客我也不知道是不是一个好习惯,但是目前还不知道有什么其他更有效率的学习方法。现在的学习方法:看书,写博客。如果看明白一个东西,去写博客的话,这通常是一个浪费时间的行为,但是这个过程同样帮助自己二次记忆。并不知道写博客到底好不好。就先按照这个来吧。开始新的一本书,《Effective Java》

    第一条:考虑用静态工厂方法代替构造器
    优点

    • 静态工厂有名称(意味着什么应该都懂)
    • 不必在每次调用他们的时候都创建一个对象(可以通过单例模式联想)
    • 可以返回原类型任意子类型的对象(可以返回子类)
    • 创建待泛型的类的实例的时候,可以使代码更整洁

    这一点需要举个例子(书中例子小改动)

    class First1<K> {
      public First1() {}
    
      public static <K> First1<K> getNewInstance() {
        return new First1<K>();
      }
    }

    如果用构造器

    First1<String> first11 = new First1<String>();
    First1<Map<String, List<String>>> first12 = new First1<Map<String, List<String>>>();

    静态工厂:

        First1<String> first13 = First1.getNewInstance();

    缺点:

    • 类不含有public/protected 的构造器就无法被子类化

    举个例子

    class First2 {
      private First2() {}
    }
    
    class First3 extends First2{
       public First3(){}
    }

    上面代码在First3中会报错。父类无共有构造器,子类根本实例化不了。这时要想到设计原则中的多使用组合少使用继承。这个地方最好就不用继承了,让Frist3成为First2的一个成员变量。

    • 另一个缺点,实例化的方法和其他方法没区别。因此,在doc中不能一眼看出哪个是用来获取对象的。

    第二条:遇到多个构造器参数时使用构造器

    意思简单世界说,当构建一个对象的时候需要很多参数来创建一个对象。这时,可以重叠构造器,就是这个构造器调用下一个构造器,一个一个调用。如果参数少,这个办法比较好,如果有十个参数,想象一下。这时,可以用到JavaBean,无参构造器一个,然后不断的set各个参数,如果用这种方法,也就意味着,这个类在创建之后可以随意改动。这时,可以用下面的办法:

    
    

      interface SupBuilder<T> {
        public T build();
      }

    public class Second {
      private int firP;
      private int secP;
      private int thiP;
      private int fouP;
      private int fivP;
    
      private Second(Builder buider) {
        this.firP = buider.firP;
        this.secP = buider.secP;
        this.thiP = buider.thiP;
        this.fouP = buider.fouP;
        this.fivP = buider.fivP;
      }
    
      public static class Builder implements SupBuilder<Second>{
        private int firP;
        private int secP;
        private int thiP;
        private int fouP;
        private int fivP;
    
        public Builder(int firP, int secP) {
          this.firP = firP;
          this.secP = secP;
        }
    
        public Builder thiP(int thiP) {
          this.thiP = thiP;
          return this;
        }
    
        public Builder fouP(int fouP) {
          this.fouP = fouP;
          return this;
        }
    
        public Builder fivP(int fivP) {
          this.fivP = fivP;
          return this;
        }
    
        public Second build() {
          return new Second(this);
        }
      }
    
      public static void main(String[] args) {
        Second second = new Second.Builder(1, 2).thiP(3).fouP(4).build();
      }
    }

    SupBuilder是附加的,根据项目,感觉需要就加上。这样,创建的时候用到了什么参数非常明显易读,最重要的易读,创建之后对象是不可变的。
    怎么选择用静态工厂还是Builder,看创建对象时参数的多少。

    第三条:用私有构造器或枚举类型强化Singleton属性

    public enum Third {
      INSTANTCE
    }

    这就能保证是一个单例,现在还没有真正领悟到枚举为什么好,用了枚举就不能定义成员了。

    第四条:通过私有构造器强化不可实例化的能力

    在项目中经常会有一些Util类中只包含静态方法和静态域的类,这些通常不需要实例化,实例化与不实例化也没有什么区别。但是在没有显示的构造器的情况下会默认的提供一个公有的构造器,就导致外部可以实例化这个类。如果把这个类设计成抽象类来防止实例化(抽象类和接口不能实例化),会给其他人错觉这个类是面向继承设计的。我们只需要在这个类中提供一个私有构造器,为了避免类内部会调用这个构造器,可以抛异常,但最好的做法是在上面添加注释:

    // Noninstantialble util class
    public class Fourth {
        private Fouth(){}
    }

    注意:这样做了之后就无法被其他类继承了,因为没提供可调用的构造器。

    第五条:避免创建不必要的对象

    最简单的错误做法:

    String s = new String("word");  // nerver do this
    String s = "word";

    如果只是简单的想要一个String对象,别用new。
    对于已知不会改变的可变对象也可以重用:

      
    // wrong
    private final Date date = new Date(); public int check() { Calendar calendar = Calendar.getInstance(); calendar.set(2000, Calendar.JANUARY, 1); Date startDate = calendar.getTime(); calendar.set(2017, Calendar.JANUARY, 1); Date endDate = calendar.getTime(); if (date.getTime() > startDate.getTime() && date.getTime() < endDate.getTime()) { return 1; } return 0; }

    正确的做法:

      private final Date date = new Date();
      private static final Date startDate;
      private static final Date endDate;
    
      static {
        Calendar calendar = Calendar.getInstance();
        calendar.set(2000, Calendar.JANUARY, 1);
        startDate = calendar.getTime();
        calendar.set(2017, Calendar.JANUARY, 1);
        endDate = calendar.getTime();
      }
    
      public int check() {
        if (date.getTime() > startDate.getTime() && date.getTime() < endDate.getTime()) {
          return 1;
        }
    
        return 0;
      }

    没修改的做法在compare方法中,没进一次方法就会创建一个Calendar对象,两个Date对象。修改后的只会在实例化类的时候分别创建出来,在方法中不断的重用。上面的做法对于创建实例后经常调用compare方法的程序,性能会有很大的提高。还有一点,如果类被实例化了,但是compare方法从来不会被调用,可以做到延迟加载,在用到compare方法的时候才去实例化,但是不建议这样做,这样会增加代码的复杂性。
    现在java提供自动装箱的操作,自动装箱使基本类型和自动装箱类型变的模糊起来。看下面的代码:

        Long sum = 0L;
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
          sum += i;
        }
        System.out.println(sum);

    没进行一次+=操作,就会将根据long的数值重新生成一个Long,在进行下一次+=的时候,将Long转成long。会创建很多多余的对象。这里将Long类型的sum定义成long类型,效率就很提高很多。
    这里说的不要创建多余对象并不是说尽量不创建对象,这里只是对于可以重用的对象只建一个然后不端重用。对于经常变的对象,不用考虑这点。

    第六条:消除过期的对象
    第七条:避免使用终结方法(finalizer)

    在《深入了解java虚拟机》中有类似的内容。不在重复。

  • 相关阅读:
    Hibernate读书笔记Hibernate的关联映射之11关联映射
    Hibernate读书笔记Hibernate的关联映射之NN关联映射 .
    Hibernate读书笔记Hibernate的关联映射之N1关联映射
    Hibernate读书笔记继承映射
    String类型转换的三种方法分析
    使用using关键字对连接进行简化
    Hibernate读书笔记继承映射
    关于ORACLE的ora12505报错以及连接问题的解决及相关资料
    10天学会Web标准建站
    Oracle中大对象(lob)处理方法
  • 原文地址:https://www.cnblogs.com/badboyf/p/6282359.html
Copyright © 2020-2023  润新知