码迷,mamicode.com
首页 > 其他好文 > 详细

创建和销毁对象

时间:2016-07-13 19:36:37      阅读:148      评论:0      收藏:0      [点我收藏+]

标签:

1. 怎样让一个类不能被实例化

应该保证类中有且仅有私有构造器。

因为如果类中不含有显式构造器,那么编译器会自动提供一个公有的无参构造器,所以类中必须得有构造器。

而且这些构造器还必须为私有类型的,否则就会被实例化或者子类化。

 

2. 避免创建不必要的对象

2.1 重复利用对象

如果一个对象需要被重复利用,可以预先构建好实例,避免创建不必要的重复对象。可参考单例模式。

 

根据一个 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());
    }
}

当然,代码就变得有点复杂了。

所以,在代码的复杂程度和性能方面我们要做出权衡,例如上述代码就这么一行对于性能是毫无影响的,所以没有必要把代码搞得那么复杂。总之得视情况而定。

 

2.2 正确使用 String

尽量不要使用如下的方式去创建 String 对象,每次都会创建出一个新实例,然后返回这个实例的引用。

String str = new String("abc");

更好的方式如下,这样的好处是如果 JVM 的常量池中正好有 ”abc“ 这个字符串对象的话,就不会创建任何对象,然后返回 "abc" 字符串对象的引用。

String str = "abc";

 

 

2.3 优先使用基本类型

要优先使用基本类型而不是装箱基本类型。

 

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

 

第一个循环的计算过程:

  • l1 -> long 类型,i1 -> int 类型;
  • i1 -> long 类型,与 l1 相加得到一个 long 类型;
  • 将得到的 long -> Long 后继续循环;

第二个循环的计算过程:

  • l1 -> long 类型;
  • i2 -> long 类型,与 l1 相加得到一个 long 类型;
  • 将得到的 long -> Long 后继续循环;

第三个循环的计算过程:

  • i1 -> int 类型;
  • i1 -> long 类型,与 l2 相加得到一个 long 类型后继续循环;

第四个循环的计算过程:

  • i2 -> long 类型,与 l2 相加得到一个 long 类型后继续循环;

 

结论:装箱基本类型在做运算的时候是先转化为基本类型再去做运算的,所以优先使用基本类型。

 

3. 消除过期的对象引用

对象用完了要记得回收。

 

下面是 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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!