<%@ page contentType="text/html; charset=gb2312"%> 有效使用final关键字的准则
网站公告:   ◆北天JAVA技术网热情为java爱好者服务,本网内容包括JAVA(JSP、servlet、EJB、webservice、j2ee、javabean、应用服务器、JavaScript),数据库(MYSQL、SQL Server、Sybase、Oracle、DB2、数据库综合知识),设计研究(设计模式、Struts、Spring、Hibernate、设计框架、设计综合知识),WEB2.0新技术(主要介绍AJAX),以及各种技术的入门、实例、例子等等,欢迎各位多来坐坐!◆  诚邀各位JAVA爱好者加盟!◆  本网站内容丰富,更新快,保证每周20篇以上!  
加入收藏
设为首页
联系站长
承接项目
  相关资源:网站首页 | 免费培训学院 | 技术论坛 | JAVA聊天室 | 作家专栏 | 开发工具 | 认证考试 | 会员俱乐部
  JAVA技术初学者园地 | jsp与servlet | javascript | Java源代码 | EJB | web service | 应用服务器 | JAVA综合知识
  设计研究设计模式 | 设计框架 | Struts | Spring | Hibernate | 开源项目 | 面向对象设计 | 设计综合知识
  数 据 库MYSQL | SQL Server | Sybase | Oracle | DB2 | Informix | Access | 数据库综合知识
  其他资源:AJAX新技术 | 网站开发 | ERP软件 | OA办公软件 | 商业智能BI | 开发综合知识 | 承接项目 | 项目试用

 
 
有效使用final关键字的准则
     发布者: 发布时间:2007-12-20
 

final 关键字常常被误用 - 声明类和方法时使用过度,而声明实例字段时却使用不足。本月,Java 实践者 Brian Goetz 探究了一些有关有效使用 final 的准则
如同它的“表亲”- C 中的 const 关键字一样,根据上下文,final 表示不同的东西。final 关键字可应用于类、方法或字段。应用于类时,意味着该类不能再生成子类。应用于方法时,意味着该方法不能被子类覆盖。应用于字段时,意味着该字段的值在每个构造器内必须只能赋值一次而且此后该值永远不变。


大多数 Java 文本都适当地描述了使用 final 关键字的用法和后果,但是很少以准则的方式提供有关何时使用 final 及使用频率的内容。根据我的经验,final 非常过度地用于类和方法(通常是因为开发人员错误地相信这会提高性能),而在其用武之地 - 声明类实例变量 - 却使用不足。


为什么这个类是 final?


对于开发人员来说,将类声明为 final,却不给出为何作出这一决定的说明,这样的做法很普遍,在开放源码项目中尤其如此。一段时间之后,特别是如果原来的开发人员不再参与代码的维护,其它开发人员将总是发问“为何类 X 被声明成 final?”。通常没人知道,当有人确实知道或喜欢猜测时,答案几乎总是“因为这能使它运行得更快”。普遍的理解是:将类或方法声明成 final 会使编译器更容易地内联方法调用,但是这种理解是不正确的(或者至少说是大大地言过其实了)。


final 类和方法在编程时可能是非常大的麻烦 - 它们限制您选择重用已有的代码和扩展已有类的功能。有时有很好的理由将类声明成 final(如强制不变性),此时使用 final 的益处将大于其不便之处。性能提高几乎总是成为破坏良好的面向对象设计原则的坏理由,而当性能提高很小或者根本没有提高时,则它真正是个很差的权衡方法。


过早优化


出于性能的考虑,在项目的早期阶段将方法或类声明成 final 是个坏主意,这有多个原因。首先,早期阶段设计不是考虑循环计算性能优化的时候,尤其当此类决定可能约束您使用 final 进行设计。其次,通过将方法或类声明成 final 而获得的性能优势通常为零。而且,将复杂的有状态的类声明成 final 不利于面向对象的设计,并导致体积庞大且面面俱到的类,因为它们不能轻松地重构成更小更紧凑的类。


和许多有关 Java 性能的神话一样,将类或方法声明成 final 会带来更佳的性能,这一错误观念被广泛接受但极少进行检验。其论点是:将方法或类声明成 final 意味着编译器可以更加积极地内联方法调用,因为它知道在运行时这正是要调用的方法的版本。但这显然是不正确的。仅仅因为类 X 编译成 final 类 Y,并不意味着同样版本的类 Y 将在运行时被装入。因此编译器不能安全地内联这样的跨类方法调用,不管是不是 final。只有当方法是 private 时,编译器才能自由地内联它,在这种情况下,final 关键字是多余的。


另一方面,运行时环境和 JIT 编译器拥有更多有关真正装入什么类的信息,可以比编译者作出好得多的优化决定。如果运行时环境知道没有装入继承 Y 的类,那么它可以安全地内联对 Y 方法的调用,不管 Y 是不是 final(只要它能在随后装入 Y 子类时使这种 JIT 编译的代码无效)。因此事实是,尽管 final 对于不执行任何全局相关性分析的“哑”运行时优化器可能是有用的,但它的使用实际上不支持太多的编译时优化,而且智能的 JIT 执行运行时优化时不需要它。


似曾相识 - 重新回忆 register 关键字


final 用于优化决定时和 C 中不赞成使用的 register 关键字非常相似。让程序员帮助优化器这一愿望促成了 register 关键字,但事实上,发现这并不是很有用。正如我们在其它方面愿意相信的那样,在作出代码优化决定方面编译器通常比人做得出色,在现在的 RISC 处理器上更是如此。事实上,大多数 C 编译器完全忽略了 register 关键字。早先的 C 编译器忽略它是因为这些编译器根本就不起优化作用;现今的编译器忽略它是因为编译器不用它就能作更好的优化决定。任何一种情况下,register 关键字都没有添加什么性能优势,和应用于 Java 类或方法的 final 关键字很相似。如果您想优化您的代码,请坚持使用那些可以大幅度提高性能的优化,比如使用有效的算法且不执行冗余的计算 - 将循环计算优化留给编译器和 JVM 去做。


使用 final 保持不变性


虽然性能并不是将类或方法声明为 final 的好理由,然而有时仍有充足的理由编写 final 类。最常见的是 final 保证那些旨在不发生变化的类保持不变。不变类对于简化面向对象程序的设计非常有用 - 不变的对象只需要较少的防御性编码,并且不要求严格的同步。您不会在您的代码中构建这一设想:类是不变的,然后让某些人用使其可变的方式来继承它。将不变的类声明成 final 保证了这类错误不会偷偷溜进您的程序中。


final 用于类或方法的另一个原因是为了防止方法间的链接被破坏。例如,假定类 X 的某个方法的实现假设了方法 M 将以某种方式工作。将 X 或 M 声明成 final 将防止派生类以这种方式重新定义 M,从而导致 X 的工作不正常。尽管不用这些内部相关性来实现 X 可能会更好,但这不总是可行的,而且使用 final 可以防止今后这类不兼容的更改。


如果您必须使用 final 类或方法,请记录下为什么这么做


无论何种情况,当您确实选择了将方法或类声明成 final 时,请记录下为什么这样做的原因。否则,今后的维护人员将可能疑惑这样做是否有好的原因(因为经常没有);而且会被您的决定所约束,但同时还不知道您这样做的动机是为了得到什么好处。在许多情况下,将类或方法声明成 final 的决定一直推迟到开发过程后期是有意义的,那时您已经拥有关于类是如何交互及可能如何被继承的更好信息了。您可能发现您根本不需要将类声明为 final,或者您可以重构类以便将 final 应用于更小更简单的类。


final 字段


final 字段和 final 类或方法有很大的不同,以至于我觉得让它们共享相同的关键字是不公平的。final 字段是只读字段,要保证它的值在构建时(或者,对于 static final 字段,是在类初始化时)只设置一次。正如较早讨论的那样,对于 final 类和方法,您将总是问自己是否真的需要使用 final。对于 final 字段,您将问自己相反的问题 - 这个字段真的需要是可变的吗?您可能会很惊讶,这个答案为何常常是“不需要”。


文档说明价值


final 字段有几个好处。对于那些想使用或继承您的类的开发人员来说,将字段声明成 final 有重要的文档说明好处 - 这不仅帮助解释了该类是如何工作的,还获得了编译器在加强您的设计决定方面的帮助。和 final 方法不同,声明 final 字段有助于优化器作出更好的优化决定,因为如果编译器知道字段的值不会更改,那么它能安全地在寄存器中高速缓存该值。final 字段还通过让编译器强制该字段为只读来提供额外的安全级别。


极端情况下,一个类,其字段都是 final 原语或对不变对象的 final 引用,那么该类本身就变成是不变的 - 事实上这是一个非常方便的情况。即使该类不是完全不变的,使其某部分状态不变可以大大简化开发 - 您不必为了保证您正在查看 final 字段的当前值或者确保没有其他人在更改对象状态的这部分而保持同步。


那么为什么 final 字段使用得如此不足呢?一个原因是因为要正确使用它们有点麻烦,对于其构造器能抛出异常的对象引用来说尤其如此。因为 final 字段在每个构造器中必须只初始化一次,如果 final 对象引用的构造器可能抛出异常,编译器可能会报错,说该字段没有被初始化。编译器一般比较智能化,足以发现在两个互斥代码分支(比如,if...else 块)的每个分支中的初始化恰好只进行了一次,但是它对 try...catch 块通常不会如此“宽容”。例如,大多数 Java 编译器不会接受清单 1 中的代码:

清单 1. final 引用字段的无效初始化
public class Foo {
  private final Thingie thingie;

  public Foo() {
    try {
      thingie = new Thingie();
    }
    catch (ThingieConstructionException e) {
      thingie = Thingie.getDefaultThingie();
    }
  }
}


但是它们会接受清单 2 中的代码,它相当于:

清单 2. final 引用字段的有效初始化
public class Foo {
  private final Thingie thingie;

  public Foo() {
    Thingie tempThingie;
    try {
      tempThingie = new Thingie();
    }
    catch (ThingieConstructionException e) {
      tempThingie = Thingie.getDefaultThingie();
    }
    thingie = tempThingie;
  }
}


final 字段的局限性


final 字段仍然有一些严重的限制。尽管数组引用能被声明成 final,但是该数组的元素却不能。这意味着暴露 public final 数组字段的或者通过它们的方法将引用返回给这些字段的类(例如,清单 3 中所示的 DangerousStates 类)都不是不可改变的。同样,尽管对象引用可以被声明成 final 字段,而它所引用的对象仍可能是可变的。如果您想要使用 final 字段创建不变的对象,您必须防止对数组或可变对象的引用“逃离”您的类。要不用重复克隆该数组做到这一点,一个简单的方法是将数组转变成 List,例如清单 3 中所示的 SafeStates 类:

清单 3. 暴露数组引用使类成为可变的
// Not immutable -- the states array could be modified by a malicious
caller
public class DangerousStates {
  private final String[] states = new String[] { "Alabama", "Alaska", ... };

  public String[] getStates() {
    return states;
  }
}


// Immutable -- returns an unmodifiable List instead
public class SafeStates {
  private final String[] states = new String[] { "Alabama", "Alaska", ... };
  private final List statesAsList
    = new AbstractList() {
        public Object get(int n) {
          return states[n];
        }

        public int size() {
          return states.length;
        }
      };
       
  public List getStates() {
    return statesAsList;
  }
}


为什么不继承 final 以应用于数组和引用的对象,类似于 C 和 C++ 中 const 的使用那样呢?C++ 中 const 的语义和使用相当混淆,根据它在表达式中所出现的位置表示不同的东西。Java 架构设计师设法把我们从这种混淆中“解救”出来,但遗憾的是他们在这个过程中产生出了一些新的混淆。


结束语


要对类、方法和字段有效使用 final,有一些基本的准则可以遵循。特别要注意的是,不要尝试将 final 用作性能管理工具;要提高您的程序的性能,有更好且约束更少的方法。在反映您程序的基本语义处使用 final:用来指示这些类将是不可改变的或那些字段将是只读的。如果您选择创建 final 类或方法,请确保您清楚地记录您为何这么做 - 您的同事会感激您的。



(转载文章请保留出处:北天JAVA技术网(www.java114.com))
 
更多精彩文章:
对EJB中Session Bean的见解
JAVA高级:多核线程-volatile原理与技巧
JAVA中具有实例缓存的不可变类
深入探讨、理解Java的CLASSPATH
JAVA基础知识精华总结
JSP、Struts避免Form重复提交的几种方案
 
最近评论:
        
buying wow account
上海buying wow account公司是上海地区专业的buying wow account公司.欢迎联系上海buying wow account公司的buying wow account服务,作为上海知名buying wow account公司之一提供buying wow account设计,画册buying wow account作品,中国buying wow account设计网,一个寻找buying wow account灵感的地方!提供最有价值的buying wow account设计buying wow account公司的杰出代表语翼上海buying wow account公司是中国优秀的语言buying wow account服务提供商!语翼buying wow account公司依托强大buying wow account资源中国buying wow account人网是综合性的buying wow account行业网站,包括对buying wow account媒介、buying wow account创意、buying wow account市场等buying wow account文章和buying wow account讨论区6787673@WOWGOLDS.COM
        
wow gold
是专业的wow gold交流、wow gold交易平台。为wow gold企业免费提供wow gold电子商务平台,wow gold企业可以向游客发布wow gold产品相关信息以及同行wow gold报价6787671@WOWGOLDS.COM
        
wow gold
中国网络wow gold网提供专业的网络wow gold知识,包括网络wow gold新闻、网络wow gold技巧wow gold公司,wow gold牌施工图,wow gold户外论坛,CEO,wow gold资讯,耗材,wow gold基本风压资料等等.在线wow gold论坛是专业wow gold人社区,发表wow gold公司总裁的wow gold观点,wow gold开展学术研究北京,wow gold公司:wow gold公司.最初是由wow gold界资深人士组成的一家专业wow gold公司,wow gold公司.
        
google排名
中国google排名下载网,第一个专业的google排名下载与欣赏类站点,关注最新的google排名资讯、提供公益google排名,6787671@WOWGOLDS.COM
        
wow gold
中国wow gold总库是一个wow gold最专业最系统的wow goldB 2B商务平台,wow gold采用“网上wow gold线下,wow gold双网合一”6787671@WOWGOLDS.COM
        
google排名
西安报纸google排名报价,西安电视google排名报价,华商报google排名报价,西安楼宇电视google排名楼梯杭州google排名网、杭州google排名公司;google排名设计公司、杭州户外google排名、杭州google排名印刷厂北京google排名公司,提供google排名管理方案,有着长久的google排名服务经验,需要google排名的人请联系我们google排名公司,google排名选择我们。 包括公益google排名、旅游google排名、商业google排名等等。然而google排名,google排名日常生活中所说的“google排名”往往特指商业google排名
        
wow gold
wow gold,济南wow gold网,wow gold网,济南wow gold,山东wow gold,美食,酒店6787671@WOWGOLDS.COM
        
wow gold
首屈一指的wow gold公司,宁波wow gold公司长期服务于各级政府wow gold、宁波wow gold公司收费合wow gold公司网络wow gold发展及网络wow gold的价值网络wow gold发轫于1994年的美国wow gold。wow gold门户,玩家wow gold网,吃喝玩乐找节目,提供wow gold线路查询,专业权威的wow gold资讯信息,包括wow gold活动、wow gold优惠上海春秋wow gold社提供的wow gold预定,wow gold拍卖,wow gold自助游服务。
        
wow gold
中国江苏wow gold,wow gold频道,江苏省最大的wow gold信息资讯平台,这里有最全wow gold最新的wow gold资讯旅行社看好节后wow gold ... 全省“诚信wow gold示范单位”—星级wow gold饭店93家. 投诉wow gold企业黑榜 ... 十一wow gold维权注意事项:wow gold投诉需要注意时效西安报纸wow gold报价,西安电视wow gold报价,华商报wow gold报价,西安楼宇电视wow gold楼梯重庆wow gold信息网是重庆wow gold资讯中心,为重庆wow gold的门户网站。提供wow gold全面的重庆wow gold资讯.h0O1l3a@lalael.com
        
鍥炲
        
标 题:   
内 容:   
 
                                  
 
免责声明:该文章由网友发表,如果对您造成侵权,请联系站长

首页 - 承接项目 - 网站地图 - 联系我们 -
版权所有北天JAVA技术工作室 ICP证号:粤ICP备06079815号