`
2007yn
  • 浏览: 44320 次
  • 性别: 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中怎样避免创建不必要的对象

    为减少内存消耗,可以考虑使用不可变集合(如Collections.unmodifiableList()、Collections.unmodifiableMap()),或者使用预设容量的容器,避免不必要的扩容操作。例如,使用`new HashMap(initialCapacity, ...

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

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

    使用类的对象还是指针

    "使用类的对象还是指针" ...在实际应用中,我们需要根据具体的应用场景和需求来选择使用类的对象还是指针,并且需要合理地使用new关键字来创建对象指针,以避免不必要的内存占用和内存碎片的出现。

    解决实例化时自动补全不必要的单词问题

    ### 解决实例化时自动补全不必要的单词问题 在编程过程中,自动补全是现代集成开发环境(IDE)中一个非常实用的功能,它可以帮助开发者更快地完成代码编写,并减少潜在的语法错误。然而,在某些情况下,自动补全...

    .NET性能优化方法 学习笔记 (详细整理版)

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

    六十一条面向对象分析设计的经验原则

    39. **避免过于复杂的对象**:保持对象设计简单,避免不必要的复杂性。 40. **对象间的交互应简洁**:减少对象间的交互次数,简化交互逻辑。 41. **对象应能自我验证**:对象应能够验证自身状态的有效性。 42. **...

    QTP:虚拟对象需要注意的两点

    因此,在设计测试脚本时,应尽量避免不必要的虚拟对象使用。 总之,正确理解和使用虚拟对象对于提高QTP自动化测试的效率和准确性至关重要。通过对虚拟对象集合的有效管理和合理使用,可以显著提升测试脚本的质量,...

    前端大厂最新面试题-improve_render.docx

    因此,需要采取措施来提升运行性能,避免不必要的渲染。 二、避免不必要的渲染 1. shouldComponentUpdate shouldComponentUpdate 是 React 中的一个生命周期函数,它可以通过比较 state 和 props 来确定是否需要...

    【原】unity 不销毁对象的处理

    9. **代码优化**:编写高效的代码,减少不必要的计算和更新。使用`StartCoroutine`和`yield`关键字可以实现异步操作,避免阻塞主线程。 10. **利用Unity的内置系统**:如Unity的物理系统、粒子系统等,它们内部优化...

    对象字段变化比较工具

    5. **性能优化**:考虑到可能处理大量数据,工具需要优化比较算法,避免不必要的计算,提高效率。 6. **版本控制集成**:如果工具能够与版本控制系统(如Git)集成,可以进一步追踪字段变化的历史,这对于源代码...

    对象作为函数参数

    ### 对象作为函数参数 在面向对象编程语言如C++中,对象作为函数参数是非常常见的用法。根据传递方式的不同,可以将对象...在实际开发中,通常建议尽可能使用引用或指针来避免不必要的对象复制,从而提高程序的性能。

    C++l临时对象

    例如,避免不必要的临时对象创建可以提高程序的性能。此外,正确地处理临时对象的生命期也是十分重要的。以下是一些注意事项: - **避免使用临时对象初始化引用**:由于临时对象的生命期很短,一旦初始化完成后就会...

    深刻理解对象设计及面向对象设计

    同时,要遵循接口隔离原则,使接口只包含相关联的职责,避免提供不必要的功能。 GRASP,全称为General Responsibility Assignment Software Principles,是一组面向对象设计的指导原则,包括以下几点: 1. **创建...

    Matlab面向对象编程

    通过抽象,我们可以忽略不必要的细节,只关注问题的关键部分。 2. 封装:封装是指隐藏对象的内部实现细节,只暴露操作接口供外界访问。在MATLAB中,通过类和对象实现封装。类定义了对象的属性和方法,而对象是类的...

    Java对象池技术的原理及其实现

    为了减少这些不必要的开销,引入了对象池技术。 #### 对象池技术的基本原理 对象池技术的核心思想在于通过缓存和共享机制来重复使用已创建的对象,而非每次都需要重新创建新的实例。这种方式显著降低了对象创建和...

    sap权限对象的创建和使用

    在SAP系统中,权限管理是企业数据安全的重要组成部分,其中权限对象扮演着核心角色。权限对象是SAP授权机制的基础,...理解并正确实施权限管理,能确保企业数据的安全,同时避免不必要的系统访问限制,提高工作效率。

    java 对象 内存 大小

    此外,合理设计对象结构,避免内存浪费,如减少不必要的引用,使用紧凑的数据结构,也可以降低内存开销。 总结来说,理解并测量Java对象内存大小对于优化内存使用、提高程序性能以及构建高效缓存系统具有重要意义。...

    deeplyAssign将所有可枚举的属性和符号属性的值从一个或多个源对象深度复制到目标对象

    同时,为了提高性能,还可以考虑添加对浅拷贝的优化,比如当检测到源对象和目标对象是同一个引用时,直接返回目标对象,避免不必要的拷贝。 `deeplyAssign-master`这个压缩包可能包含了这个函数的完整实现,包括...

    3dmax一键清除空对象

    然而,随着项目的进展,场景中可能会出现许多不必要的空对象,这些对象可能是因为历史操作或某些插件产生的。空对象在3ds Max中是指没有几何体、材质或其他实质内容的对象,它们可能会占用资源并导致场景管理上的...

Global site tag (gtag.js) - Google Analytics