2.创建和销毁对象
1.使用静态工厂方法代替构造器
一般使用构造器(构造函数)创建对象实例,还可以使用静态工厂方法来创建对象实例。
优点
使用静态工厂方法代替构造器创建对象实例有以下优点:
1)静态构造方法的名称可以是更加有意义的,具有更好的可读性,而构造器的名称必须与类名称保持一致。
2)静态工厂方法不必在每次调用时都创建一个新对象,这对于那些需要重复创建相同对象的场景下尤其有用。
3)静态工厂方法可以返回原返回类型的任意子类型对象
4)静态工厂方法在创建参数化实例的时候,使程序更加简洁。
缺点
1)使用静态工厂方法创建实例的类,一般要求构造器是私有的,也就是说这个类不能被继承,不能被子类实例化。
2)静态工厂方法与其他静态方法并没有实质的区别,不能显而易见的判断某静态方法是不是工厂方法,所以,人们就做了一个约定,静态工厂方法有一些惯用名称:例如valueOf、of、getInstance、newInstance、getType、newType。
参考:1 2
2.遇到多个构造器参数时要考虑用构建器
如果类的构造器(或者静态工厂方法)有多个参数,并且这些参数中有些是可选参数时,就要考虑使用Builder模式。
3.通过私有构造器强化不可实例化的能力
有些工具类不希望被实例化,因为实例化对它来说没有什么意思,例如java.lang.Math,java.util.Arrays。有人通过将类定义为抽象类来避免类的实例化,不过,这样容易引起误解,让用户误以为这个类是专门为了继承而设计的。我们可以通过一个简单的方法来避免类被实例化,就是显式地将类的构造器声明为私有的(private),这样就保证避免类的实例化(前提是类中的其他成员不调用这个私有的构造器)。
4.避免创建不必要的对象
也就是说最好是能够重用已有的对象,而不是在每次需要的时候就创建一个相同功能的对象。
1)如果对象是不可变的(immutable),那它始终可以被重用。基本类型的包装类、String、BigInteger和BigDecimal都是不可变类。以字符串为例:
String str=new String("Java");
这条语句执行时,每次都会创建一个新的String实例,不过这是不必要的,因为每次创建的实例是相同的,都是字符串"Java",而“Java”本身就是字符串实例。如果这种方法用在循环或者被频繁调用的方法中,就会创建成千上万个相同功能的实例。改进后的版本如下:
String str="Java"
这种方法并没有创建新实例,而是使用已创建好的“Java”实例。并且,如果在代码的其他位置,使用了相同的字符串字面常量,仍然不会创建新对象,而是仍然复用这个“Java”实例,对于其他的不可变类也是如此。
2)除了重用不可变类之外,还可以重用那些创建了之后就不会修改的可变对象。参考
6.清除过期的对象引用(内存泄漏)
一个对象,如果在程序之后的执行过程中不会再使用,正常情况下,其所在的内存区域应该被回收,以便于存储新的对象。不过,由于一些原因未被回收,还是占据着内存,导致可用内存量下降,就像内存变少了一样,称这种现象为内存泄漏。Java虽然具有垃圾回收的功能,不过也会发生内存泄漏。
1)如果是类自身管理内存,可能会发生内存泄漏。以数组实现的栈为例,栈独自管理数组所占的内存空间,代码实现如下:
1 public class Stack { 2 private Object[] elements; 3 private int size = 0; 4 private static final int DEFAULT_INITIAL_CAPACITY = 100; 5 public Stack() { 6 elements = new Object[DEFAULT_INITIAL_CAPACITY]; 7 } 8 public void push(Object e){ 9 ensureCapacity(); 10 elements[size++] = e; 11 } 12 public Object pop(){ 13 if(size == 0){ 14 throw new EmptyStackException(); 15 } 16 return elements[--size]; 17 } 18 private void ensureCapacity(){ 19 if(elements.length == size){ 20 elements = Arrays.copyOf(elements, 2 * size + 1); 21 } 22 }