我有几个我不知道的案例。首先,如果你没有构造函数:
class NoCons { int x; }
当我执行new NoCons()
时,将调用默认构造函数。它究竟做了什么?它是否将x
设置为0,还是将其设置为其他地方?
如果我遇到这种情况该怎么办:
class NoCons2 extends NoCons { int y; }
当我致电new NoCons2()
时会发生什么? NoCons
的默认构造函数是否被调用,然后是NoCons2
的构造函数?他们是否各自将x
和y
字段设置为0?
这个版本怎么样:
class Cons2 extends NoCons { int y; public Cons2() {} }
现在我有一个构造函数,但它不会调用超类的构造函数。 x
如何初始化?如果我遇到这种情况怎么办?
class Cons { int x; public Cons() {} }
class NoCons2 extends Cons { int y; }
是否会调用Cons
构造函数?
我可以尝试所有这些示例,但我无法确定何时运行默认构造函数。考虑这一点的一般方法是什么,以便我知道未来情况会发生什么?
答案 0 :(得分:13)
当Java类没有显式定义构造函数时,会添加一个公共的no-args默认构造函数,所以:
class Cons { int x; }
相当于:
class Cons { int x; public Cons() {} }
子类的构造函数没有显式定义它调用的父构造函数中的哪一个将自动调用父类中的默认构造函数之前执行其他任何操作。所以假设:
class A { public A() { System.out.println("A"); } }
然后这个:
class B extends A { public B() { System.out.println("B"); } }
完全等同于:
class B extends A { public B() { super(); System.out.println("B"); } }
,两种情况下的输出都是:
A
B
所以当你这样做时:
new NoCons2();
订单是:
答案 1 :(得分:1)
您想引用Java Language Specification section 12.5 Creation of New Class Instances来获取对象创建的官方规则。相关部分是:
在作为结果返回对新创建的对象的引用之前,处理指示的构造函数以使用以下过程初始化新对象:
- 将构造函数的参数分配给此构造函数调用的新创建的参数变量。
- 如果此构造函数以同一个类中的另一个构造函数的显式构造函数调用开始(使用此构造函数),则使用这五个相同的步骤计算参数并以递归方式处理该构造函数调用。如果该构造函数调用突然完成,则此过程突然完成,原因相同;否则,继续执行第5步。
- 此构造函数不以同一个类中的另一个构造函数的显式构造函数调用开头(使用此方法)。如果此构造函数用于Object以外的类,则此构造函数将以超类构造函数的显式或隐式调用开始(使用super)。使用这五个相同的步骤评估参数并递归处理超类构造函数调用。如果该构造函数调用突然完成,则此过程突然完成,原因相同。否则,请继续执行步骤4.
- 为此类执行实例初始化程序和实例变量初始值设定项,将实例变量初始值设定项的值按从左到右的顺序分配给相应的实例变量,在这些顺序中,它们以文本方式显示在类的源代码中。如果执行任何这些初始值设定项导致异常,则不会处理其他初始化程序,并且此过程会突然完成同样的异常。否则,继续执行步骤5.(在某些早期实现中,如果字段初始化表达式是一个常量表达式,其值等于其类型的默认初始化值,则编译器会错误地省略代码以初始化字段。)
- 执行此构造函数的其余部分。如果执行突然完成,则此过程突然完成,原因相同。否则,此过程正常完成。
醇>
因此,在您的示例中,如果类定义中未提供构造函数,则会为您插入默认构造函数。当你写
new NoCons2();
super()
调用,因为你没有显式调用)。在第一个示例中,x将在构造NoCons
期间设置,y将在构造NoCons2
期间设置。
因此,该示例中事件的确切顺序如下:
Object()
的隐式调用。答案 2 :(得分:0)
答案 3 :(得分:0)
这基本上是在调用“new”时会发生什么:
如果您不提供构造函数,编译器将执行以下操作:
因此,当调用“new”之后的类的构造函数时,它首先要调用“super()”来调用父构造函数。这种情况一直发生在java.lang.Object上。
在运行构造函数体之前,VM会执行以下操作:
以下代码显示了所有这些:
public class Main
{
private Main()
{
}
public static void main(final String[] args)
{
final Foo fooA;
final Foo fooB;
fooA = new Foo(7);
System.out.println("---------------------");
fooB = new Foo(42);
}
}
class Bar
{
protected int valueA = getValue("valueA", 1);
protected int valueB;
static
{
System.out.println("static block for Bar happens only one time");
}
{
System.out.println("instance block for Bar happens one time for each new Bar");
System.out.println("valueA = " + valueA);
System.out.println("valueB = " + valueB);
}
Bar()
{
super(); // compiler adds this - you would not type it in
System.out.println("running Bar()");
System.out.println("valueA = " + valueA);
System.out.println("valueB = " + valueB);
valueB = getValue("valueB", 2);
}
protected static int getValue(final String name, final int val)
{
System.out.println("setting " + name + " to " + val);
return (val);
}
}
class Foo
extends Bar
{
protected int valueC = getValue("valueC", 1);
protected int valueD;
static
{
System.out.println("static block for Foo happens only one time");
}
{
System.out.println("instance block for Foo happens one time for each new Foo");
System.out.println("valueC = " + valueC);
System.out.println("valueD = " + valueD);
}
Foo(final int val)
{
super(); // compiler adds this - you would not type it in
System.out.println("running Foo(int)");
System.out.println("valueC = " + valueC);
System.out.println("valueD = " + valueD);
valueD = getValue("valueD", val);
}
}