2013-12-16 48 views
6

我认为这个问题的具体用途如下,但它更加通用化。在构造函数结束之前如何引用/处理“this”?

我有一个自定义JFrame类,它也可以作为其组件的ActionListener。所以我的构造看起来像下面这样:

private JButton myButton; 

public MyCustomFrame() { 
    super(); 
    myButton.addActionListener(this); 
    // ... more stuff 
} 

我的问题是,这是如何在幕后工作?如果构造函数是“创建”this引用的对象,那么在构造函数返回之前如何使用this?代码编译和工作完全正常(据我所知),因此该对象在某种意义上必须已经“存在”,但我担心这可能会导致无法预料的问题。通过对addActionListener()的“部分构建”引用(或者只是通常对其执行任何逻辑)有没有任何危险?还是有一些幕后的魔法发生让我安全?

例如,那些没有默认值并且必须由构造函数提供的东西呢?如果我声明了private final String SOME_VALUE;,我知道这应该默认为null,但该对象不应该完全形成,直到常量在构造函数中提供一个值。那么,尽管是最终的,参考文献可能会改变价值吗?

+0

没有直接连接到你的问题,但它可以为你的目的http://stackoverflow.com/a/3404369/2350145 –

回答

9

即Java语言规范指定的instance creation

步骤[...]

接下来,空间分配给新的类实例。如果 没有足够的空间来分配对象,则通过抛出 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条目。

我找不到更具体的东西,那么上面是什么。也许在4.12.4. final Variables

最后一个变量只能被分配一次。

您可以认为默认初始化会将该值设置为0或null,并且分配会改变它。

+0

什么东西没有默认值,必须*提供*的构造函数?例如,如果我有'私有最终字符串SOME_VALUE;'声明,我明白这应该默认为'null',但该对象不应该完全形成,直到常量在构造函数中提供一个值。那么参考文献,尽管是“最终”,可能会有变化的价值? (我会将此添加到问题中。) – asteri

+0

@Jeff我试图编译一个程序,在分配final字段之前释放'this'引用,它是默认值(0或'null')。 JLS中一定有这方面的内容,我只需要找到它。 –

+0

我怀疑规格说什么,因为它是紧急行为。该字段尚未由构造函数分配,因为构造函数的代码照常按顺序运行。在分配任何变量(final或not)之前,你泄漏'this'并且Java不能奇迹般地知道你将要在那里放置什么值。 –

4

一旦你调用你的构造函数,你的对象从一开始就已经存在,并且你只是用值填充它。

如果传递对象的方法尝试使用尚未在构造函数中声明的值,则会带来危险。


你也想避免你的构造函数(和其他方法为此事)作出这样的方式构造的用户不会期望。

如果实例化对象的人没有理由期望构造函数自动将该对象绑定到按钮,那么也许你不应该那样做。

1

this在构造函数完成之前确实存在。但是,在构造函数完成之前允许引用this以逃避对象可能会带来危险。

如果您将this引用传递给假设对象已完全形成并准备就绪的方法,该怎么办?也许这对你的对象来说很好,但在很多情况下,这可能是危险的。允许其他方法在准备好使用之前访问对象会对您的程序能够可靠运行造成严重威胁。

1

你是完全正确的,这是一件坏事,因为this可能只在您使用它时被部分初始化。

这就是为什么许多编译器会给出警告。

0

不要将它从构造函数中转义出来,因为如果另一个线程读取了构造尚未完成的实例的变量,线程可能会读取意外的值。

一个例子如下。

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存储器模型规范以外的值。

相关问题