创建对象
构造方法创建对象
注意点 构造器创建对象
示例优点缺点 静态工厂方法创建对象
示例:优点缺点 总结创建对象方法 保证单例 Singleton
静态工厂方法创建单例对象
示例注意 枚举创建单例对象
示例注意 创建对象注意
不要创建不必要对象
示例注意 消除过期的对象引用
示例注意 销毁对象
避免使用销毁对象方法处理必须关闭的资源
示例原因 观 JAVA EFFECTIVE有感
创建对象 构造方法创建对象@Setter
@Getter
public class Address {
private String province;
private String city;
private String area;
public static void main(String[] args) {
Address address = new Address();
}
注意点
- 参数较少的情况下,使用构造方法较为清晰;参数多的构造方法,需要花费较多时间清楚参数含义;参数较多,使用无参构造方法,需要执行大量的set方法。每次调用构造方法,都会创建一个新对象。每次调用构造方法,返回当前类型对象,无法返回子类对象。
public static void main(String[] args) {
Address address = Address.builder().area("area").city("city").province("province").build();
}
// lombok的@Builder注解生成代码
public class Address {
private String province;
private String city;
private String area;
Address(final String province, final String city, final String area) {
this.province = province;
this.city = city;
this.area = area;
}
public static Address.AddressBuilder builder() {
return new Address.AddressBuilder();
}
public static class AddressBuilder {
private String province;
private String city;
private String area;
AddressBuilder() {
}
public Address.AddressBuilder province(final String province) {
this.province = province;
return this;
}
public Address.AddressBuilder city(final String city) {
this.city = city;
return this;
}
public Address.AddressBuilder area(final String area) {
this.area = area;
return this;
}
public Address build() {
return new Address(this.province, this.city, this.area);
}
public String toString() {
return "Address.AddressBuilder(province=" + this.province + ", city=" + this.city + ", area=" + this.area + ")";
}
}
}
优点
- 链式编程,支持可变参数。可以使用Builder创建多个对象。
创建对象前,需要创建构造器
静态工厂方法创建对象 示例:Collectors类中的静态方法 public static优点Collector > toList() { return ......; } public static Collector > toSet() { return ......; } public static Collector joining() { return ......; } public static Collector joining(CharSequence delimiter) { return joining(delimiter, "", ""); } public static Collector joining(CharSequence delimiter, CharSequence prefix, CharSequence suffix) { return new CollectorImpl<>(() -> new StringJoiner(delimiter, prefix, suffix), StringJoiner::add, StringJoiner::merge, StringJoiner::toString, CH_NOID); } Boolean类中的静态方法 public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); }
- 静态工厂方法有名称,支持望名知意。如示例中的第一、二个静态方法。不会在每次调用后创建新对象。如示例中的第六个静态方法。可以返回指定类型的子类对象。如示例中的第一、二个静态方法。返回对象随着静态方法参数值变化而变化。如示例中的第五个静态方法。
- 类中没有共有(public)/受保护(protected)的构造器,就不能被子类化。在项目中找到指定类型的静态工厂方法,有些困难。
三种方法没有优劣之分,需要根据不同场景,选择创建对象方式。
保证单例 Singleton 静态工厂方法创建单例对象 示例public final class Boolean implements java.io.Serializable, Comparable注意{ public static final Boolean TRUE = new Boolean(true); public static final Boolean FALSE = new Boolean(false); public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); } }
- 使用静态属性可以保证单例。由于用 构造方法创建对象都会创建一个新对象,因此使用private关键字修饰构造方法,在某种程度上可以保证单例。使用反射的方式,可以强行调用private的构造方法。针对这种情况,可以选择枚举保证单例。
public enum BooleanEnum {
TRUE(Boolean.TRUE),
FALSE(Boolean.FALSE),
;
private Boolean value;
BooleanEnum(Boolean value) {
this.value = value;
}
public Boolean getValue() {
return value;
}
public void setValue(Boolean value) {
this.value = value;
}
}
注意
实现单例的最佳方案。
创建对象注意 不要创建不必要对象 示例// 错误示例
boolean flag = false;
if (flag) {
return false;
} else {
return true;
}
String s = new String("test");
// 正确示例
boolean flag = false;
return !flag;
String s = "test";
注意
- 重复创建成本较高的对象,推荐缓存。举例:Pattern正则实例。优先使用基本数据类型而不是装箱基本类型。小对象的创建和回收成本不高,可以通过创建附加对象使程序逻辑清晰。除非对象是非常重量级的,否则不推荐使用 对象池 维护对象。举例:数据库连接池、线程池。
public class Stack {
private Object[] elements;
private int size = 0;
private static final int DEFAULT_INIT_CAPACITY = 16;
public Stack() {
this.elements = new Object[DEFAULT_INIT_CAPACITY];
}
public void push(Object o) {
resize();
elements[size++] = o;
}
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
return elements[size--];
}
private void resize() {
if (elements.length == size) {
elements = Arrays.copyOf(elements, size * 2 + 1);
}
}
}
注意
- 示例中的代码没有明显错误。但是随着数组中元素增加,不释放,会逐渐导致性能降低,严重的情况下会导致OutOfMemoryError错误。修复问题不复杂,pop方法如下修改即可。
public Object pop() {
if (size == 0) {
throw new EmptyStackException();
}
Object element = elements[size--];
element = null;
return element;
}
- 内存泄漏的可能原因:类自行管理内存、长时间不使用的缓存。
JVM中有一套成熟的垃圾处理机制,强行使用自定义销毁对象方法,可能出现未知的异常情况;如果自行本人开发实力比开发JVM虚拟机的大牛强,推荐自定义研发一套JVM机制。
处理必须关闭的资源推荐使用try-with-resource。
示例try (BufferedReader bufferedReader = new BufferedReader(new FileReader(path))){
return bufferedReader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
原因
相对于 try-finally处理更加优雅,finally中执行close方法可能抛出异常。
观 JAVA EFFECTIVE有感


