Java中的构造函数保证了哪些属性?

Dog*_*Dog 6 java security concurrency inheritance constructor

我曾经认为,直观地说,Java中的构造函数是创建对象的东西,并且在构造函数返回之前没有任何东西可以触及该对象.但是,我一遍又一遍地证明了这一点:

  1. 未初始化的对象可以通过共享泄露 this
  2. 未初始化的对象可以被从终结器访问它的子类泄露
  3. 未初始化的对象在完全构造之前可以泄露给另一个线程

所有这些事实都违反了我对构造函数的直觉.

我不能再自信地说出构造函数在Java中实际做了什么,或者它的用途是什么.如果我正在使用所有最终字段创建一个简单的DTO ,那么我可以理解构造函数的用途是什么,因为这与C中的结构完全相同,除非它无法修改.除此之外,我不知道在Java中可以可靠地使用哪些构造函数.它们只是一种惯例/句法糖吗?(即如果只有工厂为你初始化对象,你只会有X x = new X(),然后修改每个字段x以使它们具有非默认值 - 鉴于上述3个事实,这几乎等同于Java实际上是如何)

我可以命名两个实际上由构造函数保证的属性:如果我这样做X x = new X(),那么我知道它x是一个实例,X但不是它的子类X,并且它的最终字段已完全初始化.你可能想说你知道X完成的构造函数并且你有一个有效的对象,但是如果你传递X给另一个线程这是不真实的- 另一个线程可能会看到未初始化的版本(即你刚才所说的与没有什么不同的叫工厂的保证.建造者实际保证的其他什么属性?

Gra*_*ray 6

所有这些事实都违反了我对构造函数的直觉.

他们不应该.构造函数完全按照您的想法执行.

1:通过共享可以泄露未初始化的对象

3:未初始化的对象在完全构造之前可以泄漏到另一个线程

this在构造函数中启动线程的泄漏以及存储新构造的对象的问题,其中多个线程在没有同步的情况下访问它是围绕非最终(和非易失性)字段的初始化的重新排序的所有问题.但是初始化代码仍由构造函数完成.构造对象的线程完全看到对象.这是关于何时这些更改在其他线程中可见,而这些线程不受语言定义的保证.

您可能会想要知道X的构造函数已完成并且您有一个有效的对象,但如果您将X传递给另一个线程,这是不正确的 - 另一个线程可能会看到未初始化的版本(即您刚才所说的没有什么不同比起工厂的保证.

这是对的.如果你有一个不同步的对象并且你在一个线程中改变它也是正确的,其他线程可能会也可能不会看到突变.这是线程编程的本质.即使构造函数也不安全,无需正确同步对象.

2:未初始化的对象可以被从终结器访问它的子类泄露

本文档讨论的是终结器,并且在垃圾收集后不正确地访问对象.通过黑客子类和终结器,你可以生成一个没有正确构造的对象,但这是一个很大的黑客攻击.对我来说,这不会以某种方式挑战构造函数的作用.相反,它展示了现代,成熟的JVM的复杂性.该文档还说明了如何编写代码来解决这个问题.

Java中的构造函数保证了哪些属性?

根据定义,构造函数:

  1. 为对象分配空间.
  2. 将对象中的所有实例变量设置为其默认值.这包括对象超类中的实例变量.
  3. 为对象分配参数变量.
  4. 处理任何显式或隐式构造函数调用(在构造函数中调用this()或super()).
  5. 初始化类中的变量.
  6. 执行构造函数的其余部分.

就你的3个问题而言,#1和#3再次是关于非最终和非易失性字段的初始化是由构造该对象的线程以外的线程看到的.无法保证不同步的可见性.

#2问题显示了一种机制,如果在执行构造函数时抛出异常,则可以覆盖finalize方法以获取和不正确构造的对象.构造函数指向1-5已发生.通过hack,你可以绕过6的一部分.我想如果这会挑战构造函数的身份,那么它就是旁观者的眼睛.