【问题标题】:static method called from constructor in JavaJava中从构造函数调用的静态方法
【发布时间】:2015-05-22 15:27:31
【问题描述】:

关于 Java 静态方法的问题。

Animal() 
{ 
    this(makeRandomName());          
}

我在 Java 中有这段代码,当我创建一个动物对象时会调用它: Animal a = new Animal() makeRandomName 是一种返回字符串的方法,该方法使用Math.random() 从字符串值数组中随机获取。 如果我没有将方法 makeRandomName 指定为 static,我会收到此错误(您能解释原因):

线程“主”java.lang.RuntimeException 中的异常:无法编译 源代码 - 在超类型构造函数之前无法引用 this 被叫了

另外,当 Animal 构造函数是这样定义的:

Animal() 
{
    this.name = makeRandomName();           
}

我没有收到任何错误,不管 makeRandomName 是静态的还是非静态的。为什么? 有什么区别 this.name = makeRandomName();this(makeRandomName());

我以前从未见过this(method_name())这个语法,我只见过this.instance_variable = value,所以我有点困惑。我确信这与超级构造函数和调用方法的顺序有关,但是很高兴看到在这种情况下对方法和构造函数以及调用方法的顺序进行专家分析。非常感谢!

我被要求发布整个代码:

public class Animal {
    String name;
    Animal (String n)
    {
        this.name = n;
    }
    Animal() 
    {

        this(makeRandomName());
        //this.name=makeRandomName();

    }
    static String makeRandomName()
    {
        int x = (int) (Math.random()*5);
        String l[] = new String[] {"Zlatan", "Ibra", "Edinson", "Gigi", "T"};
        return l[x];

    }
    public static void main(String [] args)
    {
        Animal a = new Animal();
        Animal b = new Animal("M");
        System.out.println(a.name);
        System.out.println(b.name);
    }
}

【问题讨论】:

  • 请贴出所有源代码。
  • makeRandomName 是对象上的一个方法,但在您至少调用了超级构造函数之前,该对象还没有被定义。
  • 谢谢 DJClay,makeRandomName 是对象上的方法,在哪两种情况下?这两个调用如何更精确地不同? this(makeRandomName());this.name=makeRandomName();

标签: java constructor static


【解决方案1】:

对于第一个问题 - makeRandomName() 必须指定为静态的原因是因为 makeRandomName() 是一个实例方法,并且在从构造函数中调用 super 之前无法访问,这会导致类初始化。您尝试做的是在调用super 初始化类之前调用​​makeRandomName(),从而导致编译错误。

对于第二个问题 - 在您声明 this.name = makeRandomName(); 之前,有一个对 super(); 的隐式调用。 super(...); 必须始终是构造函数中的第一条语句,即使您没有明确地编写它。因此,您的第二个构造函数的实际代码是这样的:

Animal() {
    super();
    this.name = makeRandomName();
}

makeRandomName() 此时可访问,即使它被声明为非静态,因为对象已经被构造。

【讨论】:

    【解决方案2】:

    您看到此问题是因为您在运行超类构造函数之前调用了一个对象(vs Class)方法:“makeRandomName”(您将结果作为参数传递)。在任何方法可以在对象上运行之前,对象的超级构造函数必须已经执行。这就是为什么它总是在构造函数的第一行

    【讨论】:

    • 所以我在 super() 之前调用了一个对象方法(this(makeRandomName()); 假设 makeRandomName 是非静态的)。谢谢 ControlAltDel。问题: super() 是否不会作为构造函数中的第一条语句被隐式调用,即使我们没有显式键入它?这就是我所想的。它如何与其他变体一起使用? (` this.name = makeRandomName();`)
    • @Samy 如果你使用this(),那么this() 必须是第一个语句,否则super() 是第一个语句。
    【解决方案3】:

    在第一种情况this() 中,您尝试调用类构造函数,并且尝试将在该类中定义的方法的结果传递给它。您最初创建的对象此时尚未初始化,因此它试图从其自身内部访问尚未初始化的方法。必须先调用super(),然后才能访问该方法,但在这种情况下,您不能先调用super(),然后再调用this(),因为如果您将this() 放入构造函数中,则Java 要求它是构造函数中的第一个语句。

    this(makeRandomName()) 正在调用构造函数并试图将makeRandomName() 的结果传递给构造函数调用。问题是此时对象尚未初始化,因此无法调用makeRandomName()

    this.name = makeRandomName() 是在对象初始化后将makeRandomName() 的返回值分配给类的实例变量

    在构造函数中调用构造函数是没有意义的,因为你会遇到递归情况......除非有一些设计原因这样做,但在这种情况下你需要一个基本案例来突破在某个点的递归。

    【讨论】:

    • 谢谢brso05!我确实有一个问题:我一直听说在一种情况下,对象尚未初始化,因此无法调用非静态方法。在另一种情况下,对象已初始化,因此我们可以调用非静态或静态方法(没关系)。为什么this(makeRandomName()) 不初始化对象,而this.name = makeRandomName() 初始化它?我还是有点迷茫。
    • @Samy 因为如果您调用 this(makeRandomName()) 它必须是构造函数中的第一条语句,这意味着尚未对 super() 进行隐式调用(因此对象未初始化),就好像您执行this.name = makeRandomName() 然后默认情况下super() 在此行之前被隐式调用...
    【解决方案4】:

    您在super() 之前调用了您的instance method makeRandomName(),它无法访问,因为尚未创建实例/对象。

    以下构造函数有效,因为构造函数本身在构造函数主体的first line 中默认称为super()

    Animal() {
            //this(makeRandomName());
            this.name=makeRandomName();
    }
    

    您调用的以下构造函数this(),在这种情况下super() 不会在您的构造函数Animal() 中调用,但在Animal(String name) 中,不幸的是makeRandomName() 无法访问。

    Animal() {
       this(makeRandomName()); 
       //this.name=makeRandomName();
    }
    
    
    Animal(String name){
        // super() is invoked implicitly here...
    }
    

    【讨论】:

      猜你喜欢
      • 2016-08-28
      • 2018-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-24
      • 1970-01-01
      • 1970-01-01
      • 2015-11-28
      相关资源
      最近更新 更多