EffectiveJava 学习总结(一)

来源:互联网 发布:c语言游戏程序代码 编辑:程序博客网 时间:2024/06/05 03:25

一、创建和销毁对象

1、考虑用静态工厂方法代替构造器
  • 优点
    • 有名称,易于管理和理解
    • 不必每次都创建一个新对象
    • 可以返回任何子类型的对象
      • 例如写服务端接口,根据用户的参数init不同的service存入Map,key就是用户参数,需要哪个业务就用那个service
    • 参数实例化的时候使代码变得更加简介
      • new hashMap< String, Object>();如果静态工厂方法通过泛型返回这个,就不用写这么多了。现在好像也不用非要指明了,这是一种思想
  • 缺点
    • 最主要的是必须要有构造器,否则不能被子类化(不能被继承)
    • 与一般的静态方法实际上没有任何区别,这个就需要约定
  • 代码见下载包的chapter02-item01,下载地址:effective java中文第2版示例代码
2、遇到多个构造器参数时要考虑用构建器
  • 其他常用方法的缺点
    • 普通构造器,参数多了的话各种组合麻烦不说,而且名称都一样,只能通过传递的参数来判断是什么逻辑
    • javaben模式,set的话挺直观,但是有严重的缺点,构造被分到了几个调用中,不一定能保证javabean处于一致的状态,需要保证线程安全
  • 构建器(Builder)
    • 优点
      • 又有安全性,又有可读性,编写也容易
    • 缺点
      • 实例化对象的时候需要先创建构造器
      • 参数少的时候有些冗余
    • 描述
      • 让用户利用所有必要的参数调用构造器(或静态工厂),得到一个builder对象,然后客户端在builder对象上调用类似于setter的方法,来设置每个相关的可选参数,最后客户端调用无参的build方法来生成不可变的对象
      • 内部类实现,类似于mybatis generator生成的bean
    • 代码
public class NutritionFacts {        private final int servingSize;        private final int servings;        private final int calories;        private final int fat;        private final int sodium;        private final int carbohydrate;        // 构造方法        private NutritionFacts(Builder builder) {            servingSize = builder.servingSize;            servings = builder.servings;            calories = builder.calories;            fat = builder.fat;            sodium = builder.sodium;            carbohydrate = builder.carbohydrate;        }        // 构建器        public static class Builder {            private final int servingSize;            private final int servings;            private int calories = 0;            private int fat = 0;            private int carbohydrate = 0;            private int sodium = 0;            // 构建器的构造方法            public Builder(int servingSize, int servings) {                this.servingSize = servingSize;                this.servings = servings;            }            public Builder calories(int val) {                calories = val;                return this;            }            public Builder fat(int val) {                fat = val;                return this;            }            public Builder carbohydrate(int val) {                carbohydrate = val;                return this;            }            public Builder sodium(int val) {                sodium = val;                return this;            }            public NutritionFacts build() {                // 把构架器Build传入NutritionFacts类的构造方法                return new NutritionFacts(this);            }        }        // 测试        public static void main(String[] args) {            NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8)                    .calories(100).sodium(35).carbohydrate(27).build();        }    }
3、用私有构造器或者枚举类型强化Singleton属性
  • 单例模式的一般实现
    • 模式看了一篇文章: 单例模式的七种写法
    • 本书的作者推荐使用枚举类型,并且称为实现Singleton的最佳方法
      • 更加简洁
      • 无偿提供了序列化机制
      • 绝对防止多次实例化
      • 防止反射攻击
    • 代码
    public enum Elvis {        INSTANCE;        public void leaveTheBuilding() {            System.out.println("Whoa baby, I'm outta here!");        }        public static void main(String[] args) {            Elvis elvis = Elvis.INSTANCE;            elvis.leaveTheBuilding();        }    }
4、通过私有构造器强化不可实例化的能力
  • 解释:有些类比如静态类,工具类不想被实例化,这些类实例化毫无意义,但是编译器会默认一个构造方法,在已发行的API里面就经常能看到一堆毫无意义的方法。
  • 解决:显式的声明构造方法,然后定义为private
  • 缺点:继承它的子类将没有默认的超类构造方法可用,都需要声明构造方法
  • 其他:在私有构造方法中加:throw new AssertionError();会防止类内部实例化,并不是必须的
  • 个人看法:估计这个我们是用不到了。思想很好,在多用组合少用继承的大方向下这个很能提现专业
5、避免创建不必要的对象
  • 代码
private static final Date BOOM_START;  // 在静态域内初始化        private static final Date BOOM_END;     // 在静态域内初始化        static {            Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));            gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);            BOOM_START = gmtCal.getTime();            gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);            BOOM_END = gmtCal.getTime();        }        public boolean isBabyBoomer() {            return birthDate.compareTo(BOOM_START) >= 0                    && birthDate.compareTo(BOOM_END) < 0;        }
  • 解释:将只需要创建一次的对象放入静态域里防止多次创建
  • 注意:
    • 防止无意识的自动装箱,在运算的时候使用基本类型
    • 小对象只做很少量的显式工作,所以小对象的创建和回收动作是非常廉价的,能提升程序的清晰性、简洁性和功能性,一般是好事。所以要看现实,注意不要创建不必要的对象
6、消除过期的对象引用
  • java是自动内存管理的,但是有一些漏洞
  • 如果一个栈先是增长,然后再收缩,那么从栈中弹出来的对象将不会当作垃圾回收
  • 代码:将弹出的对象设为null即可
Object result = elements[--size];    element[size] = null;
  • 总结
    • 不用过分小心,如果是一个不那么复杂的方法,方法结束则自动清理了
    • 一般而言,一旦元素被释放了,则该元素中包含的任何对象引用都应该被清空
7、避免使用终结方法
  • 作者很直接,明确finalizer是应该避免的
原创粉丝点击