2012-03-27 31 views
30

Tôi có một lớp học, Super:Quy tắc ra lệnh kế thừa các biến tĩnh trong Java là gì?

public class Super { 
    public static String foo = "foo"; 
} 

Tôi cũng có một lớp khác, Sub kéo dài Super:

public class Sub extends Super { 
    static { 
     foo = "bar"; 
    } 

    public static void main (String[] args) { 
     System.out.println(Super.foo); 
    } 
} 

Khi tôi chạy nó, nó in ra bar.
thứ ba (và cuối cùng) Lớp học của tôi là Testing:

public class Testing { 
    public static void main (String[] args) { 
     System.out.println(Super.foo); 
     System.out.println(Sub.foo); 
     System.out.println(Super.foo); 
    } 
} 

in này:

foo 
foo 
foo 

Tôi không hiểu tại sao các nội dung của foo thay đổi tùy theo những gì lớp bạn đang truy cập nó từ . Bất cứ ai có thể giải thích?

+2

Điều tôi ngụ ý bởi câu lệnh đó là khi tôi truy cập nó từ 'Testing', nó trả về một cái gì đó khác với khi tôi truy cập nó từ' Sub'. – jmgrosen

+0

'@jmgrosen: 'Ah, với bạn bây giờ. –

+3

FWIW, lưu ý sự khác biệt quan trọng giữa những gì bạn có ở trên và những gì bạn sẽ có nếu 'Sub' chứa' public static String foo = "bar"; '(trong đó bạn nhận được" foo "," bar "," foo "như bạn có thể mong đợi). –

Trả lời

33

Tôi không hiểu tại sao nội dung của foo thay đổi tùy thuộc vào lớp bạn đang truy cập.

Về cơ bản đó là vấn đề khởi tạo kiểu. Giá trị của foo được đặt thành "bar" khi Sub được khởi tạo. Tuy nhiên, trong lớp học Testing của bạn, tham chiếu đến Sub.foo thực sự được biên dịch thành tham chiếu đến Super.foo, vì vậy nó không kết thúc khởi tạo Sub, vì vậy foo không bao giờ trở thành "bar".

Nếu bạn thay đổi mã kiểm tra của bạn để:

public class Testing { 
    public static void main (String[] args) { 
     Sub.main(args); 
     System.out.println(Super.foo); 
     System.out.println(Sub.foo); 
     System.out.println(Super.foo); 
    } 
} 

Sau đó, nó sẽ in ra "thanh" bốn lần, bởi vì báo cáo kết quả đầu tiên sẽ buộc Sub được khởi tạo, trong đó sẽ thay đổi giá trị của foo. Nó không phải là vấn đề mà nó được truy cập từ đâu cả.

+2

Điều này có vẻ đúng, nhưng bạn có biết tại sao 'Sub.foo' được biên dịch thành' Super.foo'? – jmgrosen

+4

@jmgrosen: Có - bởi vì chỉ có một biến, được khai báo bởi 'Super'. Như maerics nói, nó có thể truy cập "thông qua" 'Sub', nhưng điều đó không có nghĩa đó là một biến khác. –

+0

là trường hợp tương tự cho các thành viên cuối cùng cũng –

27

Biến tĩnh trong Java không được kế thừa, chúng chỉ tồn tại trong lớp khai báo chúng; tuy nhiên, chúng có thể được truy cập ngầm định bằng cách tham chiếu đến một cá thể hoặc phân lớp (hoặc thể hiện lớp con) của lớp xác định biến tĩnh. (Xử lý biến tĩnh là một trong số ít những phần khó hiểu của ngôn ngữ Java, IMHO.)

Trong mã ví dụ của bạn, lớp Sub có một initializer tĩnh mà thay đổi giá trị của Super.foo (mặc dù trông như nó thay đổi riêng của mình phiên bản kế thừa của biến "foo"). Tuy nhiên, lớp kiểm tra không thực sự tải lớp Sub (có lẽ thông qua một số thủ thuật biên dịch?) Vì vậy nó không chạy trình khởi tạo tĩnh, vì vậy giá trị của "foo" không bao giờ bị thay đổi.

+1

Tất cả các truy cập ngầm và việc đúc ngầm ẩn là xấu đối với việc học. ** PSA: ** có tùy chọn bật mã hóa và biên dịch rõ ràng. – NoName

0

Thành viên tĩnh không được kế thừa trong java vì chúng là thuộc tính của lớp và chúng được tải trong khu vực lớp học. họ chẳng liên quan gì đến việc tạo ra vật thể. tuy nhiên chỉ có các lớp con mới có thể truy cập các thành viên tĩnh của các lớp cha của chúng.

0

Không quan trọng bạn thay đổi giá trị của biến tĩnh, nó là cùng một biến số foo, trong Sub hoặc Super.Việc bạn tạo và sửa đổi các đối tượng bạn tạo và sửa đổi là không quan trọng đối với số lượng new Sub hoặc new Super. Sự thay đổi sẽ được nhìn thấy ở khắp mọi nơi, kể từ Super.foo, Sub.foo, obj.foo chia sẻ cùng một mảnh storage.This làm việc với các kiểu dữ liệu cũng:

class StaticVariable{ 
     public static void main(String[] args){ 
      System.out.println("StaticParent.a = " + StaticParent.a);// a = 2 
      System.out.println("StaticChild.a = " + StaticChild.a);// a = 2 

      StaticParent sp = new StaticParent(); 
      System.out.println("StaticParent sp = new StaticParent(); sp.a = " + sp.a);// a = 2 

      StaticChild sc = new StaticChild(); 
      System.out.println(sc.a);// a = 5 
      System.out.println(sp.a);// a = 5 
      System.out.println(StaticParent.a);// a = 5 
      System.out.println(StaticChild.a);// a = 5 
      sp.increment();//result would be the same if we use StaticParent.increment(); or StaticChild.increment(); 
      System.out.println(sp.a);// a = 6 
      System.out.println(sc.a);// a = 6 
      System.out.println(StaticParent.a);// a = 6 
      System.out.println(StaticChild.a);// a = 6 
      sc.increment(); 
      System.out.println(sc.a);// a = 7 
      System.out.println(sp.a);// a = 7 
      System.out.println(StaticParent.a);// a = 7 
      System.out.println(StaticChild.a);// a = 7 
     } 
} 
class StaticParent{ 
     static int a = 2; 
     static void increment(){ 
      a++; 
     } 
} 
class StaticChild extends StaticParent{ 
     static { a = 5;} 
} 

Bạn có thể tham khảo một biến/phương pháp tĩnh thông qua đối tượng (như sc.a) hoặc thông qua tên lớp học của nó (như StaticParent.a). Tốt hơn là sử dụng ClassName.staticVariable để nhấn mạnh tính chất tĩnh của biến/phương pháp và để cung cấp cho trình biên dịch cơ hội tốt hơn để tối ưu hóa.

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