`
2007yn
  • 浏览: 42934 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

避免不必要的对象

阅读更多

一般来说,最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。重用方式既快速,又流行。如果对象是不可变的,它就始终可以被重用。

最为一个极端的反面例子,考虑下面的语句:

String s = new String("string");// Don't do this!

 

该语句每次被执行的时候都创建一个新的String实例,但是这些创建对象的动作全都是不必要的。传递给String构造器的参数("string")本身就是一个String实例,功能方面等同于构造器创建的所有对象。如果这种用法是在一个循环中,或者是在一个被频繁调用的方法中,就会创建出成千上万不必要的String实例。改进后:String s="stirng";

这个版本只用了一个Stirng实例,而且每次执行的时候都创建一个新的实例。而且,它可以保证,对于所有的同一台虚拟机中运行的代码,只要它们包含相同的字符串字面常量,该对象就会被重用。

例如:静态工厂方法Boolean.valueOf(String)几乎总是优先于构造器Boolean(String)。构造器在每次被调用的时候都会创建一个新的对象,而静态工厂方法则从来不要求这样做,实际上也不会这样做。

public class Person{

      private final Date birthDate;
      public boolean isBabyBoomer(){
      Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
     gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);
     Date boomStart = gmtCal.getTime();
     gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);
     Date boomEnd = gmtCal.getTime();
     return birthDate.compareTo(boomStart ) >=0      &&birthDate.compareTo(boomEnd ) <0;
    }
}

 看看这段代码有什么不妥,isBabyBoomer每次被调用的时候,都会新建一个Calendar,一个TimeZone和两个Date实例,这是不必要的,下面的版本用一个静态的初始化器,避免了这种效率低下的情况:

class Person{
       private final Date birthDate;
       private static final Date BOOM_START;
       private static final Date BOOM_END;
       static{
            Calendar gmtCal=Calendar.getInstance(TimeZone.getTimeZone("GMT"));
            gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);
            BOOM_START = gmtCal.getTime();
            gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);
            BOOM_END= gmtCal.getTime();

     }
     public boolean isBabyBoomer(){
            return birthDate.compareTo(BOOM_START;)>=0 &&birthDate.compareTo(BOOM_END)<0;
    }
}

 

改进后的Person类只在初始化的时候创建Calendar,TimeZone和Date实例一次,而不是在每次调用isBodyBoomer的时候都创建这些实例。如果isBodyBoomer方法被频繁的调用,这种方法将会显著提高性能,代码的含义也更加清晰,但是这种优化并不总是那么明显,因为Calendar实例的创建代价特别昂贵。

如果改进后的Person类被初始化了,他的isBodyBoomer方法却永远不会被调用,那就没有必要初始化BOOM_START,BOOM_END域。通过延迟加载,即可对这些域的初始化延迟到isBodyBoomer方法第一次被调用的时候进行,则有可能消除这些不必要的初始化工作,但是不建议这样做。正如延迟初始化中常见的情况,这样会使方法的实现更加复杂,从而无法将性能显著提高到超过已经达到的水平。

再如:自动装箱问题

public static void main(String[] args){
     Long sum=0L;
     for(long i = 0; i<Integer.MAX_VALUE;i++){
          sum+=i;
    }
    System.out.println(sum);
}

 这段程序算出的答案是正确的,但是比实际情况要慢些,因为之前声明的sum是Long型,而不是long型,这样在运行的时候就会创建出2的31次方个实例,会大大消减效率,结论很明显:要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱。

不要错误的以为本文介绍的内容暗示“创建对象的代价非常昂贵,我们应该尽可能地避免创建对象”。相反,由于小对象的构造器只做很少量的显示工作,所以,小对象的创建和回收动作是非常廉价的,特别是在现在的JVM实现上更是如此。通过创建附加的对象,提升程序的清晰性,简洁性和功能性,这通常是件好事。

分享到:
评论

相关推荐

    Android中怎样避免创建不必要的对象

    并发垃圾处理器在Android 2.3中引入,但是总是应该避免不必要的工作,因此应该在不必要的时候避免创建对象实例。 在编程开发中,内存的占用是我们经常要面对的现实,通常的内存调优的方向就是尽量减少内存的占用。 ...

    k8s-objectmatcher:Kubernetes对象匹配器库,以避免不必要的K8s对象更新

    该库旨在提供更好的对象匹配功能,以避免不必要的更新和客户端上的更多可观察性。 旧版本弃用通知 有一个旧版本的lib,现在已弃用并在此处记录: 它是如何工作的? 该库使用kubectl apply在kubectl apply使用的...

    partools:单机多核大数据结构的Python并行处理。 避免对只读大数据结构进行不必要的复制

    避免对只读大数据结构进行不必要的复制。 它包括: 1. map功能的并行版本。 它旨在以内存高效的方式在具有多个内核的单台机器上执行无限并行化的任务。 在大多数情况下,它可以直接替代标准地图功能,并利用多核的...

    .net性能优化宝典

    1.1.1 避免不必要的对象创建... 4 1.1.2 不要使用空析构函数 ★... 4 1.1.3 实现 IDisposable 接口... 4 1.2 String 操作... 5 1.2.1 使用 StringBuilder 做字符串连接... 5 1.2.2 避免不必要的调用 ToUpper 或...

    map-cache:缓存从函数返回的数据,以避免不必要的调用!

    它在后台使用JS Map对象存储数据。 动机 我经常需要缓存通过API调用检索到的数据,但是大多数可用的软件包已经过时,类型不完全或者不能完全满足我的需要。 科技类 打字稿 特征 高性能的Map对象将以光速返回数据! ...

    VC代码的编写和调试

    一个好的设计应该反映问题本身的要求,而不必为了刻意追求“满足将来的需要”而添加不必要的特性。实际上,简单优雅的设计比那些复杂的设计更能迎合未来的需求。  2 耦合性  耦合(decoupling)性用来衡量不同...

    基于C#的文本分析程序

    该程序采用的语言是C#,使用的IDE为Microsoft Visual Studio 2013,采用的面向对象的程序设计思想,将文本处理与数据io写成便于调用的类库,若尝试直接打开源文件运行,请使用2013级以上版本,避免不必要的错误。

    .NET性能优化方面的总结

    火龙果软件工程技术中心 从2004年底开始接触C#到现在也有2年多... 1.1.1避免不必要的对象创建 由于垃圾回收的代价较高,所以C#程序开发要遵循的一个基本原则就是避免不必要的对象创建。以下列举一些常见的情形。 1.

    关于oracle10供了类似操作系统中的回收站功能

    有了回收站,能够减少很多不必要的麻烦。常常看到开发人员误删除表,我们可以充分利用10g的闪回(FLASHBACK)功能来避免类似的人为操作。不能对已经放到回收站(Recycle Bin)中的对象执行DDL/DML语句。

    中间件ICE中文文档手册

    3.避免不必要的复杂性,使平台更易于学习和使用。 4.提供一种在网络带宽、内存使用和CPU 开销方面都很高效的实现。 5.提供一种具有内建安全性的实现,使它适用于不安全的公共网络。 更简单地说,Ice的设计目标可陈述...

    Microsoft.IO.RecyclableMemoryStream:一个为.NET MemoryStream对象提供池以提高应用程序性能的库

    Microsoft.IO.RecyclableMemoryStream 一个为.NET ...允许多种方式读取和写入数据,以避免不必要的分配 提供出色的可调试性和日志记录 提供性能跟踪指标 特征 语义与原始System.IO.MemoryStream实现非常接近

    从实例谈面向对象编程、工厂模式和重构

    我们发现一些不必要的设计时,还需要果断地删掉这些冗余代码。 引用内容 Public void BtnPlay_Click(object sender,EventArgs e) { IMediaFactory factory = null; switch (cbbMediaType.SelectItem.ToString()....

    shscrap(用以打开ssh文件)

    SHS文件是一类特殊的OLE(ObjectLinkingandEmbedding,对象连接和嵌入)对象,可以由Word文档或Excel电子表格创建。一般在XP系统上发生,现在win7...建议各位在操作时最好知道是什么文件扩展名,避免造成不必要的麻烦。

    WEB CAD中二次开发绘制任意线功能代码如何写?

    同时,为了避免出现不必要的重叠和绘制异常,可以在每次绘制前清空 Canvas 画布。 实现网页 CAD 绘制任意线的基本思路和代码要根据实际需求进行修改和扩展,比如增加颜色、宽度等属性选择,或者支持多种绘图模式(如...

    jsonex:Java对象序列化器和反序列化器为JSON格式。 专注于配置友好性,任意对象序列化和紧凑的JSON格式

    JSONCoder 描述 Jsonex JSONCoder是一个轻量级的通用对象序列化/反序列化库,类似于Jackson,GSON或FastJson。...自定义引号字符(通过选择其他引号字符(例如Javascript)避免不必要的转义) 与ES6中一样的多行字

    第一节–面向对象编程

    &lt;Core&gt;&gt; | = 中Classes and Objects一章的笔记 | = 翻译为主+个人心得 | = 为避免可能发生的不必要的麻烦请勿转载,谢谢 | = 欢迎批评指正,希望和所有PHP爱好者共同进步! | = PHP5研究中心: ...

    超级有影响力霸气的Java面试题大全文档

    wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。 17、...

Global site tag (gtag.js) - Google Analytics