技术控

    今日:126| 主题:49289
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] Java对象初始化顺序

[复制链接]
tobe3213 发表于 2016-10-3 07:16:41
87 2

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
最近我发现了一个有趣的问题,这个问题的答案乍一看下骗过了我的眼睛。看一下这三个类:
  1. package com.ds.test;

  2. public class Upper {
  3. String upperString;

  4. public Upper() {
  5.   Initializer.initialize(this);
  6. }
  7. }
复制代码
  1. package com.ds.test;

  2. public class Lower extends Upper {

  3. String lowerString = null;

  4. public Lower() {
  5.   super();
  6.   System.out.println("Upper:  " + upperString);
  7.   System.out.println("Lower:  " + lowerString);
  8. }

  9. public static void main(final String[] args) {
  10.   new Lower();
  11. }
  12. }
复制代码
  1. package com.ds.test;
  2. public class Initializer {
  3. static void initialize(final Upper anUpper) {
  4.   if (anUpper instanceof Lower) {
  5.    Lower lower = (Lower) anUpper;
  6.    lower.lowerString = "lowerInited";
  7.   }
  8.   anUpper.upperString = "upperInited";
  9. }
  10. }
复制代码
运行 Lower 这个类可以得到什么输出?在这个极简的例子中可以更容易地看到整个形势,但是这个情形发生在现实中会有非常多的代码分散一个人的注意力。
  不管怎么样,输出是像这样的:
  1. Upper:  upperInited
  2. Lower:  null;
复制代码
虽然小示例中使用了 String 类型,Initializer 类的实际代码中有一个用于注册的委托对象,与 Lower 类的功能是相同的 — 至少 Lower 类是这个意图。但由于某些原因在运行应用程序时没有工作。取而代之的是,使用了默认路径,委托对象没有被设置 (null)。
  现在稍微改变一下 Lower 的代码:
  1. package com.ds.test;

  2. public class Lower extends Upper {

  3. String lowerString;

  4. public Lower() {
  5.   super();
  6.   System.out.println("Upper:  " + upperString);
  7.   System.out.println("Lower:  " + lowerString);
  8. }

  9. public static void main(final String[] args) {
  10.   new Lower();
  11. }
  12. }
复制代码
现在的输出是这样的:
  1. Upper:  upperInited
  2. Lower:  lowerInited
复制代码
发现代码中的区别了吗?
  是的,这个 lowerString 字段不再明确地设置为空。为什么这么做会有不同。不管怎样参考类型字段(例如这里的 String )的默认值不是为空的吗?当然是空的。事实证明,虽然这种微小的变化显然不会以任何方式改变代码行为,但是却让结果变的不同。
  那么,到底发生了什么?当查看初始化顺序的时候一切就变的清晰了:
  1.main() 函数调用了 Lower 构造器。
  2.Lower 的一个实例被准备好了。意味着所有的字段都被创建并且填充了默认值,例如,引用类型的默认值为空,布尔类型的默认值为 false 。在这个时候,任何的对字段的内联赋值都没有发生。
  3.父类构造器被调用了。这是被语言的特性所强制执行的。所以在其他任何事发生之前,Upper 的构造器被调用了。
  4.Upper 这个构造器运行并且指定了一个引用,指向 Initializer.initialize() 方法新创建的的实例。
  5.Initializer 类为两个字段( upperString 和 lowerString )附上新字符串。通过使用有点肮脏的 instanceof 实例检查做到为那两个字段赋值 – 这不是一个特别好的          设计模式    ,但是也有可行的,不用管那么多。一旦发生了,upperString 和 lowerString 的引用都不再为空。  
  6.Initializer.initialize() 的调用完成,Upper 构造器也同样完成。
  7.现在变得有趣了:Lower 实例的构造在继续。假设在 lowerString 字段的声明中没有明确地 =null 赋值,Lower 构造器恢复执行并且打印出两个连接到字段的字符串。
  然而,如果有一个明确地赋值 null 的操作,执行流程会略有不同:当父类构造器完成后,在其余的构造器运行前,任何变量初始化都会执行(参见java语言规范12.5节)。在这种情况下,之前赋值给 lowerString 的字符串引用不会再一次被赋予 null 。然后继续执行其余的函数构造,现在打印 lowerString 的值为: null 。
  这是一个很好的例子,不仅方便我们如何注意一些创建对象的细节(或者知道去哪里查看 Java 编码规范,打印的或者在线的),还显示了为什么像这样写初始化是很糟糕的。我们一点都不应该关心 Upper 的子类。相反的,如果因为一些原因对某些字段的初始化不能在子类本身被完成,它将只需要它自己的某些初始化帮助类的变体。在这种情况下,如果你使用 String lowString 或者 String lowerString = null 是真的没有任何区别的,它应该是什么就会是什么。
  原文链接:    Daniel Schneller翻译:ImportNew.com -hunter  
译文链接:[]
友荐云推荐




上一篇:JAVA程序员必知的一些事
下一篇:A list of container software
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

我请你吃饭 发表于 2016-10-7 02:59:20
不要为那些不愿在你身上花费时间的人而浪费你的时间.
回复 支持 反对

使用道具 举报

12323213 发表于 2016-11-14 09:27:03
楼主,笑一个,萌萌哒!
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表