笔记3~6

来源:互联网 发布:mysql数据库笔试题 编辑:程序博客网 时间:2024/05/16 06:10

3、用私有构造器或者枚举类型强化Singleton属性

singleton指仅仅被实例化一次的类

1.公有静态成员是final域:

public class A{public static final A INSTANCE=new A();private A(){}}

2.静态工厂方法:

public class A{public static final A INSTANCE=new A();private A(){}        public static A getInstance(){ return INSTANCE };}
3.包含单个元素的枚举类型

public enum A{INSTANCE;}
这种方法在功能上与公有域方法相近,但是他更加简洁,无偿的提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。

4、通过私有构造器强化不可实例化的能力

企图通过将类做成抽象类来强制该类不可被实例化是行不通的,该类可以被子类化,并且该子类可以被实例化。这样做容易误导用户,以为这种类是专门为了继承而设计的。

简单的确保类不会被实例化的方法:

由于只有当类不包含显式的构造器的时候,编译器才会生成缺省的构造器,因此我们只需要让这个类包含私有构造器。

5、避免创建不必要的对象

以下方法isBabyBoomer检查person是否在1946-1965间出生

public class Person{//未初始化private final Date birthDate;public boolean isBabyBoomer(){Calendar gmtCal=Calendar.getInstance(TimeZone.getTimeZone("GMT"));gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);Date boomStart=gmtCal.getTime();gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);Date boomEnd=gmtCal.getTime();return birthDate.compareTo(boomStart)>=0&&birthDate.compareTo(boomEnd)<0;}}
每次调用都会新建一个Calendar,一个timezone,两个Date实例。以下使用静态的初始化器

public class Person{//未初始化private final Date birthDate;static {Calendar gmtCal=Calendar.getInstance(TimeZone.getTimeZone("GMT"));gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);Date boomStart=gmtCal.getTime();gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);Date boomEnd=gmtCal.getTime();}public boolean isBabyBoomer(){return birthDate.compareTo(boomStart)>=0&&birthDate.compareTo(boomEnd)<0;}}
改进后只在初始化的时候才创建实例,而不是在每次调用isBabyBoomer的时候都创建的实例。

如果改进后的person类被初始化了,它的的isBabyBoomer方法却永远不会被调用,那就没有必要初始化boomStart了,通过延迟初始化(lazily Initializing)即把对这些域的初始化延迟到第一次被调用的时候进行,则有可能消除这些不必要的初始化工作,但是不建议这么做。这样做会使方法的实现更加复杂,从而无法将性能显著提高到超过已经达到的水平。

6、消除过期的对象引用

“内存泄漏“的例子

public class Stack{private Object[] elements;private int size=0;private static final int DEFAULT_INITIAL_CAPACITY=16;public Stack(){elements=new Object[DEFAULT_INITIAL_CAPACITY];}public void push(Object e){ensureCapacity();elements[size++]=e;}public Object pop(){if(size==0)throw new EmptyStackException();return elements[--size];}private void ensureCapacity(){if(elements.length==size)elements=Arrays.copyOf(elements, 2*size+1);}}
栈中弹出来的对象将不会被当做垃圾回收,即使使用栈的程序不再引用这些对象,它们也不会被回收。这是因为栈内部维护着对这些对象的过期引用(obsolete reference)。

改进:

<pre name="code" class="java">public Object pop(){<span style="white-space:pre"></span>if(size==0)throw new EmptyStackException();Object result =elements[--size];elements[size]=null;return result;}

清空过期引用的另一个好处,如果它们以后又被错误的解除引用,程序会立即抛出NullPointerException异常,而不是悄悄地运行下去。尽快地检测程序中的错误总是有好处的。


0 0
原创粉丝点击