Java 实例变量和构造函数
关于这个问题,我问了好几个问题,但似乎每次我得到答案,我都会有更多的问题。 这个问题是我另一个问题的继续: 无论如何,考虑下面的例子。Java 实例变量和构造函数,java,constructor,instance-variables,Java,Constructor,Instance Variables,关于这个问题,我问了好几个问题,但似乎每次我得到答案,我都会有更多的问题。 这个问题是我另一个问题的继续: 无论如何,考虑下面的例子。 class A{ //1 int a = 1; //2 } 我听说这个概念上看起来像 class A { //1 int a = 0; //2 A() { //3 super(); //4 a = 1; //
class A{ //1
int a = 1; //2
}
我听说这个概念上看起来像
class A { //1
int a = 0; //2
A() { //3
super(); //4
a = 1; //5
}
据我所知,这是因为每次创建对象时,实例对象都会初始化为其默认值
System.out.print(i);
在两个示例的第2行的正下方,顶部将打印1,底部将打印0。据我所知,初始化块是在构造函数之前执行的。那么,这仅仅是构造函数的概念表示吗?或者,当调用默认构造函数时,代码实际上会发生这样的更改吗?有人能帮我澄清一下吗正如你所说,你的问题中两个类之间的等价性只是概念上的
事实上,如果非静态数据字段具有初始化值,则会在调用构造函数之前对其进行初始化。编译器将初始化块复制到每个构造函数的开头(在
super
行之后),因此在字段初始化之后和构造函数代码本身之前执行初始化块。示例之间的区别在于操作顺序。在您的第一个示例中,对于您所说的初始值设定项块,顺序是:
a
(在声明中)a
(在初始化程序块中)a
(在声明中有效)a
(在初始化块中)a
(在构造函数中)super
)
这里有一个更完整的例子。考虑这个类:
class Example {
// Instance field with initializer
private int i = 5;
// Instance initialization block
{
System.out.println(this.i);
}
// constructor 1
Example() {
System.out.println(this.i * 2);
}
// constructor 2
Example(int _i) {
this.i = _i;
System.out.println(this.i * 3);
}
}
它被编译成字节码,就像这样:
class Example {
// Instance field
private int i;
// constructor 1
Example() {
// begin copied code
this.i = 5;
System.out.println(this.i);
// end copied code
System.out.println(i * 2);
}
// constructor 2
Example(int _i) {
// begin copied code
this.i = 5;
System.out.println(this.i);
// end copied code
this.i = _i;
System.out.println(this.i * 3);
}
}
在上述两种情况下,Oracle的Java8输出完全相同的字节码(在编译后使用javap-c示例查看):
从“Example.java”编译而来
课例{
示例();
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:aload_0
5:iconst_5
6:putfield#2//字段i:i
9:getstatic#3//fieldjava/lang/System.out:Ljava/io/PrintStream;
12:aload_0
13:getfield#2//字段i:i
16:invokevirtual#4//方法java/io/PrintStream.println:(I)V
19:getstatic#3//fieldjava/lang/System.out:Ljava/io/PrintStream;
22:aload_0
23:getfield#2//字段i:i
26:iconst_2
27:imul
28:invokevirtual#4//方法java/io/PrintStream.println:(I)V
31:返回
示例(int);
代码:
0:aload_0
1:invokespecial#1//方法java/lang/Object。“:()V
4:aload_0
5:iconst_5
6:putfield#2//字段i:i
9:getstatic#3//fieldjava/lang/System.out:Ljava/io/PrintStream;
12:aload_0
13:getfield#2//字段i:i
16:invokevirtual#4//方法java/io/PrintStream.println:(I)V
19:aload_0
20:iload_1
21:putfield#2//字段i:i
24:getstatic#3//fieldjava/lang/System.out:Ljava/io/PrintStream;
27:aload_0
28:getfield#2//字段i:i
31:iconst_3
32:imul
33:invokevirtual#4//方法java/io/PrintStream.println:(I)V
36:返回
}
您对如何将inta=1
转换为构造函数的描述是正确的,但这并不是全部
- 如果除了
a
,还有其他具有初始值设定项的实例字段,则它们的所有初始值设定项都将收集到一个作为构造函数一部分运行的块中
- 如果除了字段初始化外,还有通用初始化程序块,那么它们的内容将与字段初始化程序一起收集到同一块中
例如,如果你有
class A {
{
System.out.println(a);
}
int a = 1;
{
System.out.println(a);
System.out.println(b);
}
int b = 2;
{
System.out.println(b);
}
public A() {
// Code of A
}
}
然后
的代码之前的代码块如下所示:
System.out.println(a);
a = 1;
System.out.println(a);
System.out.println(b);
b = 2;
System.out.println(b);
// Code of A
现在应该很清楚为什么在初始化器前面的块中,在int a=1
之前的初始化块中打印零:初始化块不是与字段初始化器分开处理的,它们的代码混合在一起的顺序与它们在源代码中出现的顺序相同。如果未另外设置,则实例变量可立即与默认变量一起使用:对象设置为null,基元类型设置为0,false等
您有3个选项可以设置Java中实例变量的值:
1) 立即声明并实例化
class A {
int i = 1;
}
2) 在实例初始值设定项块中实例化它
class A {
int a; // it is default value 0 at this point
{ a = 1; } //instance initializer block
}
3) 在构造函数中实例化它
class A{
int a; // it is default value 0 at this point
A() {
a = 1;
}
}
在对象的实例化过程中,Java将
如果用户没有执行,首先将变量a实例化为其默认值
然后它将按照它们出现的顺序遍历任何实例初始值设定项块,最后
它将进入构造函数
检查提示:除了问问题。。。考虑到O
class A{
int a; // it is default value 0 at this point
A() {
a = 1;
}
}