Java “怎么可能?”;这";在建造师结束之前被引用/处理?
我认为这个问题的具体用途如下,但它更一般化 我有一个自定义的Java “怎么可能?”;这";在建造师结束之前被引用/处理?,java,constructor,this,Java,Constructor,This,我认为这个问题的具体用途如下,但它更一般化 我有一个自定义的JFrame类,它还充当其组件的ActionListener。因此,我的构造函数如下所示: private JButton myButton; public MyCustomFrame() { super(); myButton.addActionListener(this); // ... more stuff } 我的问题是,这在幕后究竟是如何运作的?如果构造函数“创建”了被this引用的对象,那么在构造
JFrame
类,它还充当其组件的ActionListener
。因此,我的构造函数如下所示:
private JButton myButton;
public MyCustomFrame() {
super();
myButton.addActionListener(this);
// ... more stuff
}
我的问题是,这在幕后究竟是如何运作的?如果构造函数“创建”了被this
引用的对象,那么在构造函数返回之前,我如何使用this
?代码编译和工作都非常好(据我所知),因此对象在某种意义上必须已经“存在”,但我担心这可能会导致不可预见的问题。将“部分构造”的引用传递给addActionListener()
(或只是对其执行一般逻辑)是否有任何危险?或者是幕后发生了什么让我安全的魔法
例如,对于那些没有默认值且必须由构造函数提供的东西呢?如果我有
private final String一些_值
声明,我理解这应该默认为null
,但在构造函数中为常量提供值之前,对象不应该完全形成。那么,尽管引用是最终引用,但它的值可能会发生变化吗?一旦调用构造函数,您的对象从一开始就已经存在,您只是在用值填充它
如果将对象传递给的方法试图使用尚未在构造函数中声明的值,则会出现这种情况
您还希望避免让您的构造函数(以及与此相关的其他方法)以构造函数的用户不期望的方式运行
如果实例化对象的人没有理由期望构造函数自动将该对象绑定到按钮上,那么您可能不应该这样做。
在构造函数完成之前,该
确实存在。但是,在构造函数完成之前允许引用此
来逃逸对象可能会带来危险
如果您将
这个引用传递给一个方法,该方法假定您的对象已完全成形并准备就绪,该怎么办?也许这对你的物体来说是好的,但在很多情况下,这可能是危险的。在对象准备好使用之前允许其他方法访问该对象将严重威胁您的程序能否可靠运行。Java语言规范规定了
[……]
接下来,为新类实例分配空间。如果有
空间不足,无法分配对象,无法评估类
实例创建表达式通过抛出
OutOfMemoryError
新对象包含中声明的所有字段的新实例
指定的类类型及其所有超类作为每个新字段
实例创建后,将其初始化为默认值(§4.12.5)。
接下来,计算构造函数的实际参数,
从左到右。如果任何参数计算突然完成,
不计算其右侧的任何参数表达式,并且
实例创建表达式由于相同的原因突然完成
接下来,调用指定类类型的所选构造函数。
这将导致为每个超类调用至少一个构造函数
类类型的。这个过程可以由显式的
构造函数调用语句(§8.8),并在
§12.5
因此,在调用构造函数(它是一个方法)时,您的实例以默认值存在
对于final
字段,如果您尝试访问这些字段,它们似乎也是默认的。比如说
public class Driver {
public static void main(String[] args) {
new Driver();
}
final int value;
public Driver() {
print(this);
value = 3;
}
static void print(Driver driver) {
System.out.println(driver.value);
}
}
将打印0。如果我能找到JLS条目,我马上回来
我找不到比上面更具体的了。也许在
最后一个变量只能指定一次
您可以理解为默认初始化将值设置为0或null,赋值将更改它。您完全正确,这是一件坏事,因为此
只能在您使用时部分初始化
这就是为什么许多编译器会发出警告。不要从构造函数中转义它,因为如果另一个线程读取尚未完成构造的实例的变量,该线程可能会读取意外值
下面是一个例子
public class A {
private final int value;
public A(int value) {
this.value = value;
new Thread(new Runnable() { // this escape implicitly
public void run() {
System.out.println(value);
}
}).start();
}
public static void main(String[] args) {
new A(10);
}
}
此程序可能会显示Java内存模型规范中10以外的值。对于没有默认值且必须由构造函数提供的内容,该怎么办?例如,如果我有private final String一些_值
声明,我理解这应该默认为null
,但在构造函数中为常量提供值之前,对象不应该完全形成。那么,尽管引用是最终的
,但它的值可能会发生变化吗?(我将此添加到问题中。)@Jeff我试图编译一个程序,在分配最终
字段之前释放此
引用,它是默认值(0或空
)。JLS中一定有关于这方面的内容,我必须找到它。我怀疑规范中是否有关于这方面的内容,因为这是紧急行为。该字段还没有被构造函数赋值,因为构造函数的代码像往常一样按顺序运行。您在分配任何变量(final或not)之前泄漏这个,Java无法神奇地知道您将在那里输入什么值。@TimB不神奇,但我认为可能有一些编译器的废话