Java không ghi đè trường (còn gọi là thuộc tính hoặc biến thành viên). Thay vào đó, họ shadow over lẫn nhau. Nếu bạn chạy chương trình thông qua trình gỡ rối, bạn sẽ tìm thấy hai biến số x
trong bất kỳ đối tượng nào thuộc loại B
.
Dưới đây là giải thích về những gì đang xảy ra. Chương trình đầu tiên lấy một cái gì đó là ngầm của loại A
và sau đó gọi cho x
được giả định đến từ A
. Mặc dù nó rõ ràng là một loại phụ, trong ví dụ của bạn một đối tượng kiểu B
được tạo thông qua SubCovariantTest
, nó vẫn giả định bạn trả về một cái gì đó trong getObj() được ngầm nhập A. Vì Java không thể ghi đè các trường, kiểm tra sẽ gọi A.x
và không B.x
.
CovariantTest c = new SubCovariantTest();
// c is assumed the type of CovariantTest as it is
// implicitly declared
System.out.println(c.getObj().x);
// In this method chain the following happens:
// c.getObj() will return object of type B
// BUT will assume it is an A
// c.getObj().x will return the x from A
// since in this context the compiler assumes
// it is an A and make the call to A.x
Nó có vẻ như một dấu hiệu bướng bỉnh vì các phương thức luôn được ghi đè trong Java (so với C++ và C# trong đó chúng không có). Bạn thường không gặp phải vấn đề này vì quy ước mã Java cho bạn biết không bao giờ truy cập trực tiếp vào các trường. Thay vào đó hãy chắc chắn rằng các lĩnh vực luôn luôn truy cập thông qua phương pháp accessor, tức là getters:
class A {
private int x = 5;
public int getX() { // <-- This is a typical accessor method
return x;
}
}
class B extends A {
private int x = 6;
@override
public int getX() {
// will be called instead even though B is implied to be A
// @override is optional because methods in Java are always virtual
// thus are always overridden
return x;
}
}
Mã để làm việc này là như sau:
c.getObj().getX();
// Will now call getX() in B and return the x that is defined in B's context.