美文网首页
避免创建不必要的对象--EffectiveJava小结(5)

避免创建不必要的对象--EffectiveJava小结(5)

作者: 冰鱼飞鸟 | 来源:发表于2018-08-01 23:44 被阅读0次

    尽量重用对象,而不是重新创建。

    一.重用不可变对象

    不可变对象,始终可以被重用。
    如String

    //尽量用,多次调用不会重复创建对象
    String s = "";
    //而不是,调多少次就创建多少次对象
    String s2 = new String("");
    

    另外调用静态工厂方法优于调用构造器。
    如Boolean.valueOf(String); 优于new Boolean(String)
    因为前者会返回Boolean中缓存的true和false对象,避免重复创建。

    二.重用适配器/视图对象

    适配器/视图对象是指这样一个对象:它把功能委托给一个后备对象,从而为后备对象提供一个可以替代的接口。
    由于其除了后备对象外没有其他状态信息,所以针对某个给定对象的特定适配器而言,它不需要创建多个适配器实例。

    这句话咋一看难以理解,没有代入感。下面以HashMap的keySet为例进行理解

    final class KeySet extends AbstractSet<K> {
            public final int size()                 { return size; }
            public final void clear()               { HashMap.this.clear(); }
            public final Iterator<K> iterator()     { return new KeyIterator(); }
            public final boolean contains(Object o) { return containsKey(o); }
            public final boolean remove(Object key) {
                return removeNode(hash(key), key, null, false, true) != null;
            }
            public final Spliterator<K> spliterator() {
                return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);
            }
            public final void forEach(Consumer<? super K> action) {
                Node<K,V>[] tab;
                if (action == null)
                    throw new NullPointerException();
                if (size > 0 && (tab = table) != null) {
                    int mc = modCount;
                    for (int i = 0; i < tab.length; ++i) {
                        for (Node<K,V> e = tab[i]; e != null; e = e.next)
                            action.accept(e.key);
                    }
                    if (modCount != mc)
                        throw new ConcurrentModificationException();
                }
            }
        }
        
        final class KeyIterator extends HashIterator
            implements Iterator<K> {
            public final K next() { return nextNode().key; }
        }
        
        final Node<K,V> nextNode() {
                Node<K,V>[] t;
                Node<K,V> e = next;
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
                if (e == null)
                    throw new NoSuchElementException();
                if ((next = (current = e).next) == null && (t = table) != null) {
                    do {} while (index < t.length && (next = t[index++]) == null);
                }
                return e;
            }
    

    这个KeySet类就是一个适配器/视图。

    根据视图这个名字我们就可以初步理解为KeySet这个类本身并没有存储数据,其数据来源都是其后备对象即HashMap。

    可以看到KeySet只有方法没有自己的属性,并且方法中使用的都是HashMap中的属性。程序调用KeySet的方法实际是访问了这个HashMap的方法或属性。

    这样看来如果为同一个HashMap创建多个KeySet对象并没有意义。因为修改了任何一个KeySet其实都是修改的这个HashMap。完全没有必要创建用处完全相同的多个KeySet。

    至此把上面那句话用HashMap,KeySet代入来说的话就是

    HashMap中的KeySet对象把KeySet的功能委托给这个HashMap对象来完成,从而为HashMap提供一个可以替代的接口。由于这个KeySet除了HashMap这个后备对象外,没有其他状态信息,所以针对一个给定的HashMap的KeySet而言,不需要创建多个KeySet实例。

    三.注意自动装箱导致的创建多余对象

    四.不需要过于追求性能而尽可能不创建对象。
    实际上小对象的创建和回收代价很小,如果创建新的对象可以增加程序的清晰性,简洁性和功能性,那通常是件好事。
    如为了保护原有数据而拷贝对象导致的重复创建。这时候重用对象可能会付出更大的代价。

    相关文章

      网友评论

          本文标题:避免创建不必要的对象--EffectiveJava小结(5)

          本文链接:https://www.haomeiwen.com/subject/wymdvftx.html