如何避免创建不必要的对象
2017-03-05 22:31 ttylinux 阅读(460) 评论(0) 编辑 收藏 举报本文涉及到的概念
1.在保证程序清晰性和简洁性的基础下,重用具有相同功能的对象,避免创建新的对象
2.适配器对象,adapter Object
3.自动装箱,基本数据类型和装箱类型
在保证程序清晰性和简洁性的基础下,重用具有相同功能的对象,避免创建新的对象
当该对象的状态是不变化的,新创建的对象具有的功能与原来对象相同的,那么就避免创建新的对象,直接使用原来的对象。如果代码中发现这种情况,就做出调整,调整为使用一个对象,避免使用新的对象。
例子:来自<<effective Java>>
方法isBabyBoomer,用来检查一个Person实例,该实例是不是出生在婴儿期(1946年1月到1965年1月)。Person类的每个实例,每次调用该方法,都会创建相同的boomStart对象,boomEnd对象。一次调用,创建如下对象,一个Calendar,一个TimeZone,两个Date对象。当然,它们都是局部变量,每次方法调用完后,就被销毁。
可以提高一下性能,修改为:
因为boomStart和boomEnd在所有实例中功能相同,而且还没有被修改,那么,就可以提出来,让它成为静态变量。为所有实例共用。
适配器对象,adapter Object
上面Person提取的共用的对象,它们的状态在实例化后就不会被修改。而适配器对象,它的状态会被修改。
调用Map实例的keySet方法,它每次返回的都是同一个对象。不同的线程,持有该Map对象,调用keySet方法,得到的都是同一个keySet对象。对该keySet对象的状态进行修改,要在多个线程中可见,就需要使用volatile来修饰。
Map:
public interface Map<K,V> { // Views /** * Returns a {@link Set} view of the keys contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own <tt>remove</tt> operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> * operations. It does not support the <tt>add</tt> or <tt>addAll</tt> * operations. * * @return a set view of the keys contained in this map */ Set<K> keySet(); ... } // Modification Operations /** * Associates the specified value with the specified key in this map * (optional operation). If the map previously contained a mapping for * the key, the old value is replaced by the specified value. (A map * <tt>m</tt> is said to contain a mapping for a key <tt>k</tt> if and only * if {@link #containsKey(Object) m.containsKey(k)} would return * <tt>true</tt>.) * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with <tt>key</tt>, or * <tt>null</tt> if there was no mapping for <tt>key</tt>. * (A <tt>null</tt> return can also indicate that the map * previously associated <tt>null</tt> with <tt>key</tt>, * if the implementation supports <tt>null</tt> values.) * @throws UnsupportedOperationException if the <tt>put</tt> operation * is not supported by this map * @throws ClassCastException if the class of the specified key or value * prevents it from being stored in this map * @throws NullPointerException if the specified key or value is null * and this map does not permit null keys or values * @throws IllegalArgumentException if some property of the specified key * or value prevents it from being stored in this map */ V put(K key, V value); AbstractMap: // Views /** * Each of these fields are initialized to contain an instance of the * appropriate view the first time this view is requested. The views are * stateless, so there's no reason to create more than one of each. */ transient volatile Set<K> keySet = null; transient volatile Collection<V> values = null; HashMap继承AbstractMap: entrySet不会被序列化 // Views private transient Set<Map.Entry<K,V>> entrySet = null; /** * Returns a {@link Set} view of the keys contained in this map. * The set is backed by the map, so changes to the map are * reflected in the set, and vice-versa. If the map is modified * while an iteration over the set is in progress (except through * the iterator's own <tt>remove</tt> operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt> * operations. It does not support the <tt>add</tt> or <tt>addAll</tt> * operations. */ public Set<K> keySet() { Set<K> ks = keySet; return (ks != null ? ks : (keySet = new KeySet())); } private final class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return newKeyIterator(); } public int size() { return size; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { return HashMap.this.removeEntryForKey(o) != null; } public void clear() { HashMap.this.clear(); } }
验证程序:验证keySet方法返回的对象是不是同一个对象
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class MapExample { public static void main(String[] args){ Map<String,String> one = new HashMap<String,String>(); one.put("Key1", "one"); one.put("key2", "two"); Set<String> keySet = one.keySet(); Iterator<String> iterator = keySet.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } one.put("Key3", "three"); one.put("key4", "four"); Set<String> keySet2 = one.keySet(); if(keySet2 == keySet){ System.out.println("They are same"); } Iterator<String> iterator2 = keySet2.iterator(); while(iterator2.hasNext()){ System.out.println(iterator2.next()); } } } 输出结果: Key1 key2 They are same Key1 key2 Key3 key4
自动装箱,基本数据类型和装箱类型
一个例子
public class AutoBoxingExam { public static void main(String[] args){ Long sum = 0l; for(long i = 0; i < Integer.MAX_VALUE; i++){ sum = sum + i; // sum is an Object, can not use + // so auto unboxing //sum.longValue() + i //then sum = new Long(sum.longValue()+i); //sum = new Long(sum.longValue()+i); } } }
所以整个过程运行下来,在执行过程中,创建了多余的Integer.MAX_VALUE个Long对象。Integer的最大值是2的31次方,32位可以用来表达最大的数字是2的31次方,其中1位用来做符号位
使用自动装箱时,要注意它有可能创建新的对象。
引用:
版权声明:
作者:ttylinux
本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。