Rumah > Soal Jawab > teks badan
在验证《Core Java》第9版4-5代码时,发现程序输出结果和自己理解的不太一样。
import java.util.Random;
class Employee {
private static int nextId;
private int id;
private String name = "";
private double salary;
static {
Random generator = new Random();
nextId = generator.nextInt(10000);
}
{
id = nextId;
nextId++;
}
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
public Employee(double salary) {
this("Employee #" + nextId, salary);
}
public Employee() {
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public int getId() {
return id;
}
}
public class ConstructorTest {
public static void main(String[] args) {
Employee[] staff = new Employee[3];
staff[0] = new Employee("Harry", 40000);
staff[1] = new Employee(60000);
staff[2] = new Employee();
for (Employee e : staff) {
System.out.println("id = " + e.getId() + ", name = " + e.getName()
+ ", salary = " + e.getSalary());
}
}
}
以下是输出结果:
id = 6943, name = Harry, salary = 40000.0
id = 6944, name = Employee #6944, salary = 60000.0
id = 6945, name = , salary = 0.0
根据第一条语句得出静态初始化块生成的nextId为6943,然后在初始化块中id被赋值为6943,nextId自增后为6944。再执行第一个构造函数;
那么对于第二个对象来说,就应该直接执行初始化块,此时id为6944,nextId自增为6945。
再执行第二个构造函数,此时this("Employee #" + nextId, salary);语句中的nextId应该为6945,为什么输出结果为6944呢?
迷茫2017-04-18 10:49:39
Tertib permulaan kelas ini sememangnya masalah ajaib, yang hanya boleh difahami berdasarkan hasilnya.
Saya menetapkan titik putus untuk menguji Kedua-dua staff[0] = new Employee("Harry", 40000);
dan staff[2] = new Employee();
ialah blok kod yang dilaksanakan sebelum pembina, tetapi staff[1] = new Employee(60000);
dilaksanakan terlebih dahulu kepada this("Employee #" + nextId, salary);
, kemudian blok kod, dan kemudian public Employee(String name, double salary)
Pembina.
Jika anda menggunakan 2
, blok kod mendahului pembina seperti yang anda jangkakan.
public Employee(double salary) {
// 1
this("Employee #" + nextId, salary);
// 2
// this.name = "Employee #" + nextId;
// this.salary = salary;
}
PHPz2017-04-18 10:49:39
Biasanya, pengkompil Java akan menyalin blok permulaan instance ke dalam pembina Lokasi khusus adalah selepas memanggil pembina kelas induk dan sebelum penyataan dalam pembina, tetapi terdapat pengecualian. Tutorial Java rasmi mengatakan bahawa blok permulaan akan disalin ke dalam setiap pembina, yang sebenarnya tidak ketat.
Khusus untuk contoh ini, terdapat isu yang perlu dipertimbangkan Jika pengkompil menyalin blok permulaan kepada setiap pembina, maka jika pembina lain dipanggil dalam pembina, blok pemula akan dilaksanakan dua kali seperti
dalam contohpublic Employee(double salary) {
this("Employee #" + nextId, salary); // 调用了另一个构造方法
}
Jika pengkompil menyalin kod dalam blok pemula kepada public Employee(double salary)
dan public Employee(String name, double salary)
, blok pemula ini akan dilaksanakan dua kali Untuk mengelakkan situasi ini, pengkompil membuat proses yang mudah Apabila pembina lain kelas ini dipanggil, kod blok permulaan tidak disalin ke dalam pembina ini. public Employee(double salary)
Maksudnya, apabila memulakan objek kedua, blok permulaan ini ditangguhkan sehingga selepas memanggil
dan kemudian dilaksanakan apabila this("Employee #" + nextId, salary);
dilaksanakan Oleh kerana penangguhan pelaksanaan blok permulaan, ia diputuskan untuk lulus Apabila parameter nextId digunakan, ia masih merupakan nilai yang tidak bertambah. Employee(String name, double salary)
Jika anda menukar kaedah pembinaan ini kepada
public Employee(double salary) {
// this("Employee #" + nextId, salary);
this.name = "Employee #" + nextId;
this.salary = salary;
}
Hasil keluaran akan menjadi
id = 5473, name = Harry, salary = 40000.0
id = 5474, name = Employee #5475, salary = 60000.0
id = 5475, name = , salary = 0.0
Selepas mengubah suai situasi sebelumnya, anda boleh melihat output akhir pengkompil dengan menyahkompilasi fail kelas Hanya tiga kaedah pembinaan disiarkan di sini kandungan blok secara langsung memanggil kaedah pembina lain.
public Employee(java.lang.String, double);
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String
7: putfield #3 // Field name:Ljava/lang/String;
10: aload_0
11: getstatic #4 // Field nextId:I
14: putfield #5 // Field id:I
17: getstatic #4 // Field nextId:I
20: iconst_1
21: iadd
22: putstatic #4 // Field nextId:I
25: aload_0
26: aload_1
27: putfield #3 // Field name:Ljava/lang/String;
30: aload_0
31: dload_2
32: putfield #6 // Field salary:D
35: return
public Employee(double);
Code:
0: aload_0
1: new #7 // class java/lang/StringBuilder
4: dup
5: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
8: ldc #9 // String Employee #
10: invokevirtual #10 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
13: getstatic #4 // Field nextId:I
16: invokevirtual #11 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
19: invokevirtual #12 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: dload_1
23: invokespecial #13 // Method "<init>":(Ljava/lang/String;D)V
26: return
public Employee();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String
7: putfield #3 // Field name:Ljava/lang/String;
10: aload_0
11: getstatic #4 // Field nextId:I
14: putfield #5 // Field id:I
17: getstatic #4 // Field nextId:I
20: iconst_1
21: iadd
22: putstatic #4 // Field nextId:I
25: return