在Java中,可以从哪里调用构造函数?

时间:2015-11-14 23:40:24

标签: java

此陈述是真还是假?

“可以调用构造函数的唯一方法是从另一个构造函数中。”

我认为如果对构造函数的调用前面带有关键字'new',则可以在方法(和其他地方)中调用构造函数。

这句话怎么样?对还是错?

“可以调用构造函数的唯一方法是从另一个构造函数中(使用对super()或this()的调用),或者来自静态或实例方法,静态或实例初始化程序块,甚至构造函数,如果对构造函数的调用前面是关键字'new'。“试图像调用方法一样调用构造函数(仅使用其名称)是不允许的。“

这更准确吗? “如果对构造函数的调用前面没有关键字'new',则可以调用构造函数的唯一方法是使用this()或super()作为第一个语句从另一个构造函数中。”

7 个答案:

答案 0 :(得分:2)

让我们直接进入JLS, §8.8

  

构造函数由类实例创建表达式(第15.9节),由字符串连接运算符+(第15.18.1节)引起的转换和连接以及来自其他构造函数的显式构造函数调用(第8.8.7节)调用。 [...]

     

方法调用表达式(第15.12节)永远不会调用构造函数。

因此,您引用的第一个语句在技术上是错误的,因为JLS定义使用new作为调用构造函数。

请注意,您的段落长度语句是真假信息的组合;除非通过创建新对象,否则无法从静态或实例方法调用构造函数。

答案 1 :(得分:2)

不是通过“调用” 1 来关注原始问题的作者的意思,而是以下是调用构造函数的不同方法。

  • 使用new运算符,其类名和参数与构造函数签名匹配:

        Foon f = new Foon(1, 2);
    

    也可以使用反射和相当于Constructor表达式的new对象,或者使用等效于{{1的本机代码中的相关JNI或JNA回调来执行相同的操作表达式。但是,在所有情况下,构造函数调用在概念上都发生在对象创建的同一点上。因此,我会将它们视为相同。

  • 使用new从同一个类中的另一个构造函数显式链接到构造函数。

  • 通过使用this(...)从直接子类构造函数显式链接到构造函数,或通过直接子类构造函数中隐含的super(...)隐式链接到no-args构造函数(声明或暗示)。

    隐式案例仅仅是明确的super()链式案件的“语法糖”。

还有一些其他地方,Java从常规Java代码后面调用super。一个让人想到的是字符串连接,自动装箱,以及JVM抛出某些异常; e.g。

new

1 - ......除非我们理解上下文,否则这是不可知的,包括OP的讲师(或教科书)如何使用“invoke”这个词。

答案 2 :(得分:0)

这是真的。您无法编写实际调用构造函数的代码,如下所示:

class Vehicle {
    Vehicle() { } // Constructor
    void doSomething() {
        Vehicle(); // Illegal
    }
}

答案 3 :(得分:0)

着名的虚幻建设者。 它存在于那里,即使它不在那里它仍然存在。

在创建对象时调用构造函数。

所以是的,如果你使用 new 创建一个对象,那么构造函数可以被调用,或者更确切地说,无论你在何处使用它都会被调用。

你的引用似乎不完整

  

“可以调用当前类的超类的构造函数的唯一方法是在当前类构造函数中。”

答案 4 :(得分:0)

当您将该类用作其他类中的对象时,可以使用构造函数。

MyClass mc = new MyClass();

答案 5 :(得分:0)

如果您的意思是,使用this(...)super(...)构造(称为explicit constructor invocation)直接调用同一对象的另一个构造函数,答案为yes

这可能是问题的意思,但你必须在措辞上非常精确,这个问题不是。

因为如果通过"调用"你的意思是,"导致构造函数运行"然后你可以调用"一个带有new关键字的构造函数,它首先分配并创建对象,然后运行构造函数。在这个,相当宽松的意义上,答案是否定的。

但是,重要的是,new不仅仅是调用构造函数。因此,从字面意义上讲,调用new与调用构造函数不同。就像泡茶一样需要倒入热水,但与简单地倒入热水不一样。

您是否想要做出这种区分取决于您,或者在这种情况下是问题的作者,您需要问他们。

答案 6 :(得分:0)

此声明为false。

'调用构造函数'可能意味着三件事:

  1. 您可以通过使用new运算符创建新对象来调用构造函数:

    String s = new String("abc");
    

    在这种情况下,您将首先分配一个对象,然后调用构造函数:

    NEW java/lang/String // allocate String instance
    LDC "abc"            // push the String constant on the stack
    INVOKESPECIAL "java/lang/String"."<init>" : "(Ljava/lang/String;)V" // invoke constructor
    
  2. 第二种方法是从同一个类中调用另一个构造函数:

    class Super
    {
        Super(int i) { }
    }
    class Test extends Super {
        Test() { this(1); }
        // Bytecode:
           INVOKESPECIAL "Test"."<init>" : "(I)V"
        // ---------
    
  3. 调用构造函数的第三种方法是从超类中调用一个:

        Test(int i) { super(i); }
        // Bytecode:
           INVOKESPECIAL "Super"."<init>" : "(I)V"
        // ---------
    }
    
  4. 无论哪种方式,生成的字节码都将包含INVOKESPECIAL指令。这意味着您实际上是在三个情况下调用构造函数,因此如果您定义了&#39; invoke&#39;通过该指令,有多种方法可以调用构造函数。