首页 > 其他 > 详细

如何避免创建不必要的对象

时间:2017-03-05 23:37:00      阅读:248      评论:0      收藏: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位用来做符号位
 
使用自动装箱时,要注意它有可能创建新的对象。
 
引用:
 
 

如何避免创建不必要的对象

原文:http://www.cnblogs.com/ttylinux/p/6507183.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!