2009-01-30 46 views
5

Tôi có câu hỏi về kế thừa và truyền trong Java. Tôi có hai lớp ví dụ sau và một lớp thử nghiệm, và tôi nêu câu hỏi của tôi sau khi các lớp:Thừa kế và đúc trong Java

public class Automobile { 
    public int var; 

    public Automobile() { 
     var = 1; 
    } 

    public String toString() { 
     return "AUTOMOBILE: " + var; 
    } 
} 


public class Porsche extends Automobile { 
    public int var; 

    public Porsche() { 
     var = 2; 
    } 

    public String toString() { 
     return "PORSCHE: " + var; 
    } 
} 

public class Test { 
    public static void main (String [] args) { 
     Porsche p = new Porsche(); 
     Automobile a = new Automobile(); 

     System.out.println ("(Automobile) p = " + (Automobile)p); 

     System.out.println ("(Automobile) p.var = " + ((Automobile)p).var); 
    } 
} 

Đầu ra là:

(Automobile) p = PORSCHE: 2 
(Automobile) p.var = 1 

Tôi không hiểu tại sao trong báo cáo thứ hai chúng tôi có 1. Không nên là 2? Bởi vì sau khi tôi đúc p để ô tô trong báo cáo đầu tiên tôi vẫn nhận được PORSCHE: 2 như các đại diện của p - Tôi hiểu điều này theo cách sau:

tuy nhiên tôi đã đúc p để ô tô p giữ "bản chất gốc" của nó - p là một đối tượng của lớp Porsche, nhưng bởi vì Porsche mở rộng ô tô, chúng ta có thể nói rằng p cũng là một ô tô. Và do đó khi chúng tôi đúc nó một cách rõ ràng cho ô tô, nó tiếp tục sử dụng phương pháp của nó - trong trường hợp của chúng tôi phương pháp toString() được xác định trong Porsche.

Mặt khác, nếu những gì tôi viết là đúng, sau đó báo cáo kết quả in thứ hai nên cung cấp cho 2 và không 1.

Bây giờ điều này dường như mâu thuẫn với tôi, nhưng kể từ khi công trình này trong Java, có vẻ như tôi không hiểu chuyện gì đang diễn ra trong quá trình đúc và quá trình thừa kế.

Trả lời

16

Tôi tin rằng bạn thực sự không thể ghi đè các biến trong Java. Lớp con thực sự 'ẩn' biến số var.

Khi bạn truyền tới Automobile, bạn đang nhận phiên bản của lớp bậc trên của biến số var. Tuy nhiên, phương thức toString() vẫn đang xem phiên bản của biến số var của phiên bản.

Nếu bạn đã xóa public int var khỏi phân lớp Porsche, nó sẽ hoạt động như mong đợi. Cần lưu ý rằng thực hành không tốt để sử dụng các biến cá thể công khai, bạn nên luôn luôn tạo ra các getters/setters để có một số thích hợp encapsulation.

5

Làm mờ biến số var.

Porche.var của bạn là một biến khác với Automobile.var.

Phương pháp Porsche.toString() sử dụng Porsche.var, trong khi diễn viên yêu cầu trình biên dịch sử dụng phiên bản Automobile.

2

Truy cập vào các trường không phải là đa hình - nó chỉ phụ thuộc vào loại thời gian biên dịch của biểu thức.

Biểu thức ((Ô tô) p) có kiểu thời gian biên dịch Ô tô, vì vậy các trường của nó được sử dụng.

1

Khai báo biến "var" trong cả hai lớp, thực sự tạo hai trường trong bộ nhớ.

Một thể hiện của "Porsche" sẽ có hai trường "var" trong bộ nhớ, một trong những "Porsche" lớp và một trong những siêu lớp "ô tô". Trường "var" của siêu lớp bị ẩn khi bạn tham khảo "var" từ một phiên bản "Porsche" đã biết.Nếu bạn cast instance này là "Automobile" và tham chiếu đến trường "var", bạn tham khảo trường var "Automobile".

Không ghi đè trong trường. Các trường mới có cùng tên sẽ làm lu mờ các trường của siêu lớp.

Để có được kết quả mong đợi, bạn không nên khai báo trường "var" trong lớp "Porsche".

0

Tuy nhiên:

Nếu bạn có một phương pháp mà trả về tầng lớp phụ huynh Một đối tượng, nó có thể trả lại bất kỳ đối tượng gõ một lớp mà kéo dài nó (Ví dụ về nhà máy). Bây giờ nếu phương thức này trả về một đối tượng lớp con B và nếu bạn không bỏ nó thành B, tất cả các thuộc tính của nó sẽ là các thuộc tính cha. Nếu bạn đưa nó vào B thì các thuộc tính của nó sẽ là các thuộc tính A và B.

class A { 
int a1,a2; 
public A(){} 


    public static A getInstance() { 
    return new B() ; 
    } 
} 
class B { 
int b1,b2; 
    public B() {} 

} 
class Test{ 

public static void main (String [] args) { 

    A theA = A.getInstance() ; //here theA has only a1,a2 as attributes 
    B theB = (B)theA // here theB has b1,a2 and a1,a2 as attributes 
    } 


}