EffectiveJava笔记(一) 创建和销毁对象
2017-07-01 14:41
232 查看
1. 考虑用静态工厂方法代替构造器
构造器:public Boolean(boolean value) { this.value = value; }
静态工厂方法:
public static Boolean valueOf(boolean b){ return b ? Boolean.TRUE : Boolean.FALSE; }
优点:
静态工厂方法与构造器不同的第一大优势在于, 它们有名称, 这会让代码更容易阅读, 而有多个构造器的类, 会让使用者容易混淆静态工厂方法与构造器不同的第二大优势在于, 不必在每次调用它们的时候都创建一个新的对象, 这使得不可变类可以使用预先构建好的实例, 进行重复利用, 如果程序经常请求创建相同的对象, 这项技术可以极大提升性能
静态工厂方法与构造器不同的第三大优势在于, 它们可以返回原返回类型的任何子类型的对象, 这样我们在选择返回对象的类时, 就有了更大的灵活性
静态工厂方法的第四大优势在于, 在创建参数化类型实例的时候, 它们使代码变得更加简洁
如: 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();
缺点:
静态工厂方法的主要缺点在于, 类如果不含有公有的或者受保护的构造器, 就不能被子类化, 但是这样也许会因祸得福, 因为它鼓励程序员使用多复合(多实现接口)来代替继承2. 遇到多个构造器函数时, 要考虑用构建器
静态工厂和构造器有个共同的局限性, 它们都不能很好地扩展到大量的可选参数, 如下Person p = new Person(name); Person p = new Person(name, age); Person p = new Person(name, age, sex);
随着参数数量的增加, 对象的实例化会要求有更多的构造方法, 代码会很难编写, 仍然较难以阅读, 一长串类型相同的参数会导致一些微妙的错误, 如果客户端不小心颠倒了其中两个参数的顺序, 编译器也不会出错, 那么采用JavaBeans模式呢:
Person p = new Person(); p.setName(name); p.setAge(age); p.setSex(sex);
遗憾的是, JavaBeans模式自身有着很严重的缺点, 因为构造过程被分到了几个调用中, 在构造过程中JavaBean可能处于不一致的状态.JavaBeans模式阻止了把类做成不可变的可能, 这就需要程序员付出额外的努力来确保它的线程安全, 幸运的是, 还有第三种替代方法, Builder模式:
public class Person { private final String name; private final int age; private final String sex; private Person(Builder builder) { name = builder.name; age = builder.age; sex = builder.sex; } public static class Builder { private String name; private int age; private String sex; public Builder() { } public Builder name(String val) { name = val; return this; } public Builder age(int val) { age = val; return this; } public Builder sex(String val) { sex = val; return this; } public Person build() { return new Person(this); } } } Person p = new Person.Builder().name("name").age(13).sex("man").build();
这样的客户端代码很容易编写, 更为重要的是, 易于阅读
3. 用私有构造器或者枚举类型强化Singleton属性
就是单例模式public class Elvis { private static final Elvis INSTANCE = new Elvis(); private Elvis(){} public static Elvis getInstance() { return INSTANCE; } }
4. 通过私有构造器强化不可实例化的能力
public class Elvis { private Elvis() { throw new AssertionError(); } }
这种习惯用法也有副作用, 它使得一个类不能被子类化
5. 避免创建不必要的对象
String实例化
String s = new String("stringette");
该语句每次执行的时候都创建一个新的String实例, 无论字符串字面常量是否相同, 改进后的版本如下所示:
String s = "stringette";
这个版本只用了一个String实例, 而不是每次执行的时候都会创建一个新的实例, 而且对弈同一台虚拟机中运行的代码, 只要它们包含相同的字符串字面常量, 该对象就会被重用
自动装箱拆箱
自动装箱, 它允许程序员将基本类型和装箱基本类型混用, 按需要自动装箱和拆箱 Long sum = 0L; for(long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } 这段程序算出的答案是正确的, 但是比实际情况要更慢一些, 因为变量sum被生命成Long而不是long, 以为着创徐构造了大约2的31次方个多余的Long实例, 速度上也是大打折扣, 所以, 要优先使用基本类型而不是装箱基本类型, 要当心无意识的自动装箱
6. 消除过期的对象引用
7. 避免使用终结方法
终结方法的缺点在于不能保证会被及时地执行, 而且会有严重的性能损失, 例如, 用终结方法来关闭已经打开的文件, 这是严重错误, 因为打开文件的描述符是一种很有限的资源, 由于JVM会延迟执行终结方法, 所以大量的文件会保留在打开状态及时地执行终结方法正是垃圾回收算法的一个主要功能, 这种算法在不同的JVM实现中会大相径庭, 如果程序依赖于终结方法被执行的时间点, 那么这个程序的行为在不同的JVM中运行的表现可能就会截然不同, 一个程序在你测试用得JVM平台上运行得非常好, 哦而在你最重要顾客的JVM平台上却根本无法运行, 这是完全有可能的
Java语言规范不仅不保证终结方法会被及时执行, 而且根本就不保证它们会被执行, 结论是: 不应该依赖终结方法来更新重要的持久状态
相关文章推荐
- Effective Java笔记-创建和销毁对象
- Effective java笔记2--创建于销毁对象
- Effective Java - Ch 02 创建和销毁对象笔记
- Effective Java学习笔记---创建和销毁对象
- effective java 笔记之创建和销毁对象
- Effective Java笔记一 创建和销毁对象
- Effective Java:创建和销毁对象
- 学习effective java-3创建和销毁对象之利用私有构造方法或枚举类型来强化单例的属性
- EffectiveJava 第1条 :创建和销毁对象--考虑用静态方法代替构造器
- effective java:创建和销毁对象
- Effective Java——(一)创建和销毁对象
- effective Java chapter 2创建和销毁对象
- 【JAVA学习】EffectiveJava的学习笔记--第一章 创建和销毁对象
- 学习effective java-4创建和销毁对象之利用私用构造方法强化类的非实例化
- Effective Java Note (对象的创建和销毁)
- 【总结】Effective java经验之谈,创建和销毁对象
- 学习effective java-1创建和销毁对象之静态工厂方法
- 学习effective java-6创建和销毁对象之消除过时的对象引用
- 学习effective java-7创建和销毁对象之避免使用终结器(finalizers)
- 和我一起学Effective Java之创建和销毁对象