2011-09-06 42 views
5
public class Base { 
public Base() { 
    x = 0; 
    bar(); 
} 

public Base(int x) { 
    this.x = x; 
    foo(); 
} 

public void foo() { 
    System.out.println("Base.foo : " + x); 
} 

private void bar() { 
    System.out.println("Base.bar:" + x.toString()); 
} 

protected Integer x; 
} 

    public class Derived extends Base { 
     public Derived() { 
     bar(); 
     } 
     public Derived(int x, int y) { 
     super(x); 
     this.y = y; 
     } 
     public void foo() { 
     System.out.println("Derived.foo : " + x + ", " + y); 
     } 
     public void bar() { 
     System.out.println("Derived.bar:" + x.toString() + ", " + y.toString()); 
     } 
     private Integer y; 


     public static void main(String[] args) { 
     Base b = new Derived(10, 20); 
     } 
} 

Tại sao in "Derived.foo:" 10, nulll chứ không phải 20 thay vì null? y là biến riêng của Derived, và nó đã được khởi tạo với 20. nó nằm trong phạm vi của nó .. vậy tại sao nó rỗng?Java- tại sao nó in null?

Trả lời

7

Vì hàm tạo siêu được gọi đầu tiên (super(x)). Nhà xây dựng siêu này gọi phương thức foo. Sau đó, hàm tạo Derived khởi tạo y thành 20 (this.y = y). Vì vậy, khi foo được gọi, y chưa được khởi tạo. Bạn có thể gọi phương thức overridable trong các nhà xây dựng, bởi vì, như bạn vừa nhận thấy, nó có thể gọi các phương thức ghi đè trên các đối tượng được xây dựng một phần.

+0

+1. Vâng giải thích. – Mikaveli

+2

+1, đặc biệt là cảnh báo thực hành xấu: _it có thể gọi các phương thức ghi đè trên đối tượng được tạo một phần_. –

2

Các println xuất phát từ phương pháp foo được gọi là từ 'constructor s, được gọi là từ Derived' Base constructor s (thông qua super) trước bạn khởi y. Vì vậy, giá trị null được mong đợi.

1

Khi bạn truy cập vào hàm tạo của lớp siêu y chưa được khởi tạo. Vì vậy, cuộc gọi tới foo() sẽ có nully.

2

Điều đó có nghĩa là do siêu lớp (Base) gọi hàm gọi Derived.foo() trước khi biến thành viên y đã được đặt.

Vì vậy, đây là thứ tự cơ bản của hoạt động:

main(...) 
Derived(10,20) (start constructor) 
Base(10) (start constructor) 
this.x = x 
foo() (calls Derived.foo() which prints the message you see) 

Rồi sau đó

this.y = y 
1

Nó được in bởi Derived.foo() kích hoạt bởi Super-Constructor gọi trước khi nó được khởi tạo với 20 sau đó. Vì vậy, trong khi in nó vẫn là null.

1

Tất cả các câu trả lời đều đúng nhưng lần sau bạn có thể đặt điểm ngắt trong chức năng bạn đang in một thứ gì đó. Sau đó, bạn có thể chỉ cần kiểm tra ngăn xếp cuộc gọi và folow mã bằng cách đọc các phần đang được gọi.

Bằng cách này bạn có thể truy tìm được rằng y sẽ không được khởi tạo.

Chúc may mắn! Roel

+0

Tôi cần tìm hiểu cách thực hiện điều đó, Cảm ơn! – Numerator

2

Nếu bạn làm theo các cuộc gọi từ các nhà xây dựng nó làm cho nó rõ ràng hơn:

  1. Gọi Derived(int x, int y) constructor
  2. kêu gọi các nhà xây dựng siêu Base(int x)
  3. Thiết lập x biến
  4. gọi là ghi đè foo() phương pháp
  5. Thực hiện println()
  6. Sau đó bộ các y biến

Như bạn thấy, biến y đang được đặt sau khi bạn cố gắng để in ra giá trị. Đó là lý do tại sao bạn thấy giá trị chưa được khởi tạo của null.

Gọi các phương thức ghi đè từ một hàm tạo là một lỗi phổ biến, vì nó có thể cho phép các biến chưa được khởi tạo thoát trước khi đối tượng được xây dựng hoàn chỉnh.

1

vì y chưa được khởi tạo khi hàm foo() được gọi trong hàm tạo lớp cơ sở.

chuỗi đi chính -> Có nguồn gốc (x, y) -> Cơ sở (x) -> khởi tạo x, foo(). Tuy nhiên, bởi vì bạn đang bắt đầu cuộc gọi bên trong Derived, ghi đè foo(), foo() của thực thể được thực thi bởi trình thông dịch.

Các vấn đề liên quan