【问题标题】:Why can't I refer to an instance method while explicitly invoking a constructor?为什么在显式调用构造函数时不能引用实例方法?
【发布时间】:2010-09-10 14:40:18
【问题描述】:

有谁知道为什么可以在构造函数的第一行使用this()super() 引用static 方法,而不是非静态方法?

考虑以下工作:

public class TestWorking{
    private A a = null;
    public TestWorking(A aParam){
       this.a = aParam;
    }

    public TestWorking(B bParam)
    {
        this(TestWorking.getAFromB(bParam));
    }

    //It works because its marked static.
    private static A getAFromB(B param){
        A a = new A();
        a.setName(param.getName());
        return a;
    }
}

还有以下非工作示例:

public class TestNotWorking{
    private A a = null;
    public TestNotWorking(A aParam){
       this.a = aParam;
    }

    public TestNotWorking(B bParam)
    {
        this(this.getAFromB(bParam));
    }

    //This does not work. WHY???
    private A getAFromB(B param){
        A a = new A();
        a.setName(param.getName());
        return a;
    }
}

【问题讨论】:

  • 这可能只是示例代码,但我对这段代码的担忧是,您有从埋在第三类 @987654328 中的 B 实例构造 A 实例的逻辑@.
  • 我同意你的担心。我这样做的原因如下:我在一个类中使用了一个能力有限的第三方 API,并且该类被标记为 final。唯一的方法是克隆原始对象并处理副本。我使用原始对象作为新对象的参数。出于示例的目的,我对其进行了一些修改。
  • @Koekiebox 为什么你想知道 TestNotWorking.getAFromB(bParam) 不起作用?它是实例方法。您应该创建对象或使用它。

标签: java constructor initialization


【解决方案1】:

非静态方法是实例方法。这只能在现有实例中访问,并且当您在构造函数中时实例还不存在(它仍在构建中)。

为什么会这样?因为实例方法可以访问实例(非静态)字段,这些字段在不同实例中可能具有不同的值,因此在现有的已完成实例之外的其他对象上调用此类方法没有意义。

【讨论】:

  • 这很接近,但并不准确。当您在构造函数中时,实例确实 存在,并且您可以 在它们上调用实例方法。但是,在超类的构造函数完成之前,你不能这样做。如果你想在自己的构造函数中调用它们,那很好,但超类必须完成。
  • 这不是一个准确的答案。评论也完全不明白,因为问题不是调用超级构造函数而是同一个类的构造函数当然也是因为我们需要先调用超级构造函数,但是答案和评论没有说清楚。跨度>
  • 这段代码呢? 类 ClassForTest{ ClassForTest(int k){ }; { 方法(); } ClassForTest(){ 这(1); }; int method(){return 1;} }
  • @gstackoverflow 当我像这样修改你的代码时,我得到这个异常“在显式调用构造函数时无法引用实例字段测试” public class ClassForTest { int test=0; ClassForTest(int k) { } { 方法(); } ClassForTest() { this(test);//在显式调用构造函数时不能引用实例字段测试 } int method() { return 1; } public static void main(String[] args) { new ClassForTest(); } }
  • @dannail 先创建实例(即分配空间),然后构造函数按从Object 到最派生的子类的顺序运行。如果可以在超类的构造函数完成之前调用方法,则它们可以对部分初始化的字段进行操作,这可能会违反预期条件。
【解决方案2】:

请参阅Java Language Specification 8.8.7.1。这表明

构造函数体中的显式构造函数调用语句不能引用在该类或任何超类中声明的任何实例变量或实例方法或内部类,或在任何表达式中使用thissuper;否则,会发生编译时错误。

这是因为您不能在创建实例之前调用实例方法。顺便说一句,稍后可以在构造函数中调用实例方法(尽管不是您的解决方案)。

【讨论】:

  • 或在任何表达式中使用 this 或 super;否则,会发生编译时错误请澄清
  • @Marc 表示实例在显式/隐式超类构造函数调用完成后在堆中创建,即使它的初始化尚未完成?
  • @dannail - 不,它没有。堆对象是在调用任何构造函数之前创建的。
【解决方案3】:

我认为这是因为最终实例变量尚未设置(因此您还没有实例)并且实例方法可以访问一个。而所有静态初始化都在构造函数调用之前完成。

问候, 加德

【讨论】:

    【解决方案4】:

    因为当你在构造函数中调用 this 或 super 时,你的对象还没有被构造。 (您的实例尚未完全初始化)。所以调用实例方法不会产生场景。

    【讨论】:

      【解决方案5】:

      TestNotWorking 在那个时候没有被初始化。问题是:第一个构造函数 (TestNotWorking(A aParam)) 可能会调用 super()(在内部总是如此),这意味着您将在调用超类的构造函数之前调用方法。这是违法的。

      【讨论】:

        【解决方案6】:

        如果一个方法是非静态的,那么你必须在一个对象上调用它。

        在第二个示例中,您需要创建一个 TestNotWorking 类的对象并在该对象上调用 getAFromB

        类似:

        object = new TestNotWorking();
        object.getAFromB(bParam);
        

        【讨论】:

          猜你喜欢
          • 2017-12-21
          • 1970-01-01
          • 2013-06-08
          • 1970-01-01
          • 2012-08-30
          • 1970-01-01
          • 2021-11-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多