Tôi có một câu hỏi về tính kế thừa trong các ngôn ngữ lập trình OO giống như Java. Nó xuất hiện trong lớp trình biên dịch của tôi, khi tôi giải thích cách biên dịch các phương thức và lời gọi của chúng. Tôi đã sử dụng Java làm ngôn ngữ nguồn mẫu để biên dịch.
Bây giờ hãy xem xét chương trình Java này.
class A {
public int x = 0;
void f () { System.out.println ( "A:f" ); } }
class B extends A {
public int x = 1;
void f () { System.out.println ( "B:f" ); } }
public class Main {
public static void main ( String [] args ) {
A a = new A ();
B b = new B ();
A ab = new B ();
a.f();
b.f();
ab.f();
System.out.println ( a.x );
System.out.println ( b.x );
System.out.println ( ab.x ); } }
Khi bạn chạy nó, bạn nhận được kết quả sau.
A:f
B:f
B:f
0
1
0
Các trường hợp thú vị là những trường hợp xảy ra với đối tượng ab
của kiểu tĩnh A
, là B
động. Như ab.f()
in ra
B:f
nó tuân theo các yêu cầu phương thức không bị ảnh hưởng bởi kiểu thời gian biên dịch của đối tượng mà phương thức được gọi với. Nhưng
System.out.println ( ab.x )
in ra 0
, vì vậy truy cập thành viên bị ảnh hưởng bởi các loại thời gian biên dịch.
Một sinh viên hỏi về sự khác biệt này: không nên truy cập của các thành viên và phương pháp phù hợp với nhau? Tôi không thể đưa ra một câu trả lời hay hơn "đó là ngữ nghĩa của Java".
Bạn có biết một lý do khái niệm rõ ràng tại sao các thành viên và phương pháp khác nhau theo nghĩa này không? Một cái gì đó tôi có thể cung cấp cho học sinh của tôi?
Chỉnh sửa : Sau khi điều tra thêm, đây dường như là một đặc điểm riêng của Java: C ++ và C # hoạt động khác nhau, xem ví dụ bình luận của Saeed Amiri bên dưới.
Chỉnh sửa 2 : Tôi vừa thử chương trình Scala tương ứng:
class A {
val x = 0;
def f () : Unit = { System.out.println ( "A:f" ); } }
class B extends A {
override val x = 1;
override def f () : Unit = { System.out.println ( "B:f" ); } }
object Main {
def main ( args : Array [ String ] ) = {
var a : A = new A ();
var b : B = new B ();
var ab : A = new B ();
a.f();
b.f();
ab.f();
System.out.println ( "a.x = " + a.x );
System.out.println ( "b.x = " + b.x );
System.out.println ( "ab.x = " + ab.x ); } }
Và tôi ngạc nhiên khi kết quả này trong
A:f
B:f
B:f
a.x = 0
b.x = 1
ab.x = 1
Lưu ý rằng các overrise
sửa đổi là cần thiết. Điều này làm tôi ngạc nhiên vì Scala biên dịch thành JVM và hơn nữa, khi tôi biên dịch và thực thi chương trình Java ở đầu bằng trình biên dịch / thời gian chạy Scala, nó hoạt động giống như chương trình Java.
f
vàx
, không đề cập rõ ràng về điều này, phiên bản IMO C # sẽ tốt hơn ( dễ chấp nhận hơn trong quan điểm OO), thay vì thực hiện điều này, hãy xác địnhx
,f
là ảo và bạn sẽ nhận được kết quả nhất quán bằng cách ghi đè chúng vàoB
. Nhưng nếu bạn hỏi điều này trong Stackoverflow, bạn sẽ được chú ý nhiều hơn và tôi chắc chắn câu trả lời hay.