标签:
应该保证类中有且仅有私有构造器。
因为如果类中不含有显式构造器,那么编译器会自动提供一个公有的无参构造器,所以类中必须得有构造器。
而且这些构造器还必须为私有类型的,否则就会被实例化或者子类化。
如果一个对象需要被重复利用,可以预先构建好实例,避免创建不必要的重复对象。可参考单例模式。
根据一个 boolean 值创建一个 Boolean 对象,每次调用都得新创建一个对象。
Boolean b = new Boolean(true);
再看一下 Boolean 类的部分代码:valueOf() 方法重复利用预先构建好的实例,且这些实例不会改变,因此不会总是去创建新的对象。
public final class Boolean implements java.io.Serializable,Comparable<Boolean> { 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); } }
下面在再举一个例子:
public class DateUtil{ public static String getDate(){ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); return df.format(new Date()); } }
在上面的代码中,每次调用 getDate() 方法都会创建一次 SimpleDateFormat 对象,我们可以把这段代码提取出来,就得到了下面这个样子:
public class DateUtil{ private static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); public static String getDate(){ return df.format(new Date()); } }
但是上述代码真的好吗? 如果我不去调用 getDate() 方法,那我预先构建的实例还有什么用呢,不是白白浪费了存储空间和时间吗 ?
解决办法:可以对其进行延迟初始化,如下:
public class DateUtil{ private static SimpleDateFormat df = null; public static String getDate(){ if(null==df){ df = new SimpleDateFormat("yyyy-MM-dd"); } return df.format(new Date()); } }
当然,代码就变得有点复杂了。
所以,在代码的复杂程度和性能方面我们要做出权衡,例如上述代码就这么一行对于性能是毫无影响的,所以没有必要把代码搞得那么复杂。总之得视情况而定。
尽量不要使用如下的方式去创建 String 对象,每次都会创建出一个新实例,然后返回这个实例的引用。
String str = new String("abc");
更好的方式如下,这样的好处是如果 JVM 的常量池中正好有 ”abc“ 这个字符串对象的话,就不会创建任何对象,然后返回 "abc" 字符串对象的引用。
String str = "abc";
要优先使用基本类型而不是装箱基本类型。
public static void main(String[] args) { Long l1 = 10L; long l2 = 10L; Integer i1 = 1; int i2 = 1; Calendar c1 = Calendar.getInstance(); for(int i=0;i<1000000000;i++){ l1 += i1; } Calendar c2 = Calendar.getInstance(); for(int i=0;i<1000000000;i++){ l1 += i2; } Calendar c3 = Calendar.getInstance(); for(int i=0;i<1000000000;i++){ l2 += i1; } Calendar c4 = Calendar.getInstance(); for(int i=0;i<1000000000;i++){ l2 += i2; } Calendar c5 = Calendar.getInstance(); System.out.println(c2.getTimeInMillis()-c1.getTimeInMillis()); System.out.println(c3.getTimeInMillis()-c2.getTimeInMillis()); System.out.println(c4.getTimeInMillis()-c3.getTimeInMillis()); System.out.println(c5.getTimeInMillis()-c4.getTimeInMillis()); }
上述代码最后输出如下:
4556 4305 343 328
第一个循环的计算过程:
第二个循环的计算过程:
第三个循环的计算过程:
第四个循环的计算过程:
结论:装箱基本类型在做运算的时候是先转化为基本类型再去做运算的,所以优先使用基本类型。
对象用完了要记得回收。
下面是 JDK 旧版本中的 Stack 的一段代码:
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]; } /** * Ensure space for at least one more element, roughly doubling the capacity * each time the array needs to grow. */ private void ensureCapacity() { if (elements.length == size) elements = Arrays.copyOf(elements, 2 * size + 1); } }
不难发现,如果一个栈是先增长后收缩,那么从栈中弹出来的对象就不会被当做垃圾回收。
可以通过修改 pop() 方法解决这个问题。而现在的 JDK 版本中这个问题已经解决掉了。
public Object pop() { if (size == 0) throw new EmptyStackException(); Object o = elements[--size]; elements[size] = null; return elements[--size]; }
一般来说,像 Stack 这样子的自己来管理内存的,就要注意内存泄漏问题。
标签:
原文地址:http://www.cnblogs.com/xmsx/p/5666969.html