2011-01-29 48 views
29
public class A { 
    public void f1(String str) { 
     System.out.println("A.f1(String)"); 
     this.f1(1, str); 
    } 

    public void f1(int i, String str) { 
     System.out.println("A.f1(int, String)"); 
    } 
} 



public class B extends A { 
    @Override 
    public void f1(String str) { 
     System.out.println("B.f1(String)"); 
     super.f1(str); 
    } 

    @Override 
    public void f1(int i, String str) { 
     System.out.println("B.f1(int, String)"); 
     super.f1(i, str); 
    } 
} 


public class Main { 
    public static void main(String[] args) { 
     B b = new B(); 
     b.f1("Hello"); 
    } 
} 

Tôi đang tìm kiếm rằng mã này sẽ đầu ra:Calling lớp cơ sở ghi đè chức năng từ phương pháp lớp cơ sở

B.f1(String) 
A.f1(String) 
A.f1(int, String) 

Tuy nhiên, tôi nhận được:

B.f1(String) 
A.f1(String) 
B.f1(int, String) 
A.f1(int, String) 

Tôi hiểu rằng dưới ngữ cảnh của B "this" trong A.f1 (String) là thể hiện của B. Tôi có tùy chọn thực hiện chuỗi B1(). F1 (String) -> (A's) f1 (String) -> (A's) f1 (int, String) không?

Đây là một câu hỏi lý thuyết, thực tế giải pháp rõ ràng là trong A để thực hiện một hàm riêng mà cả f1 (String) và f1 (int, String) sẽ gọi.

Cảm ơn bạn,
Maxim.

+2

Tôi đã thử sử dụng phản chiếu (nhận đối tượng Phương thức cho f1 (int, String) và gọi nó), nhưng nó không hoạt động. [Blog entry] [1] trong các blog của Sun chỉ ra rằng điều này là không thể với Java. [1]: http://blogs.sun.com/sundararajan/entry/calling_overriden_superclass_method_on – esaj

+0

@esaj Đẹp tìm thấy trên liên kết –

Trả lời

29

Thật không may, không có

Như tôi chắc chắn rằng bạn đang nhận thức, nhưng tôi sẽ nhà nước một cách rõ ràng cho đầy đủ - chỉ có 2 từ khóa để kiểm soát lời gọi phương thức:

  • này- - tìm kiếm phương pháp bắt đầu từ lớp sơ thẩm cách gọi của (các ví dụ của "top" ảo bảng - mặc định ngụ ý)
  • siêu-super.method() - tìm kiếm phương pháp bắt đầu từ lớp cha của lớp trong đó phương thức gọi được định nghĩa (bảng ảo của lớp cha mẹ gọi là - not strictly true, nhưng đơn giản hơn để nghĩ theo cách này - nhờ @maaartinus)

Tôi có thể tưởng tượng một từ khóa khác (ví dụ: ? Hiện hành) làm những gì bạn mô tả:

  • hiện-current.method() - tìm kiếm phương pháp bắt đầu từ lớp trong đó phương pháp cách gọi được định nghĩa

nhưng Java không có một từ khóa như vậy (chưa?).

+0

AFAIK, 'super.method()' không bắt đầu từ VT của cha mẹ. Không có tra cứu VT nào cả, nó hoạt động theo cách tương tự như gọi các phương thức riêng tư. AFAIK, nó được biên dịch bằng cách sử dụng invokespecial. – maaartinus

+0

@maaartinus - cảm ơn - ah, tôi thích học điều gì đó mới mỗi ngày. Vì vậy, không có lệnh 'invokevirtualstartingfromparent' -' invokespecial' được sử dụng cho 'super' call và' invokespecial' sử dụng ràng buộc thời gian biên dịch. Vì vậy, tại thời điểm gọi 'super', chúng ta biết đủ về loại để giải quyết thời gian biên dịch của phương thức đích. Nếu phương thức đó ** không được thực hiện trong lớp cha trực tiếp, thì tôi giả sử tương đương với việc tìm kiếm hệ thống phân cấp vẫn là cần thiết. Kết quả cuối cùng có hiệu quả giống nhau không? –

+0

Tôi không nghĩ rằng có bất kỳ tra cứu tại thời gian chạy, thậm chí không trong trường hợp này. IIUIC, 'super' có nghĩa là * tổ tiên đầu tiên có nó *. Trình biên dịch phải biết toàn bộ hệ thống phân cấp, vì vậy nó viết tổ tiên thích hợp trong tệp lớp. Trong trường hợp phương thức không có (chỉ có thể được thực hiện bằng các thủ thuật sử dụng một classfile khác), một NoSuchMethodError bị ném ra. – maaartinus

5

Các phương pháp ghi đè trong Java bị ràng buộc động. tức là loại thể hiện thực tế của đối tượng ra lệnh cho những gì sẽ được gọi. Các phương thức final (không thể ghi đè) và các phương thức private (không thể kế thừa) được liên kết tĩnh.

Trong C++, ngược lại, bạn phải rõ ràng thực hiện các chức năng virtual để có được cùng một hành vi.

16

Tôi sợ, đó là không thể, nhưng có một cách giải quyết đơn giản:

public class A { 
    public void f1(String str) { 
     System.out.println("A.f1(String)"); 
     privateF1(1, str); 
    } 

    private void privateF1(int i, String str) { 
     System.out.println("A.f1(int, String)"); 
    } 

    public void f1(int i, String str) { 
     privateF1(i, str); 
    } 
} 
+2

Tiền tố một cuộc gọi phương thức với 'this.' này luôn luôn thừa. –

-2
package main; 

public class A { 
public void f1(String str) { 
    System.out.println("A.f1(String)"); 
    if (this instanceof B) 
     new A().f1(1, str); 
    else 
     this.f1(1, str); 
} 

public void f1(int i, String str) { 
    System.out.println("A.f1(int, String)"); 
} 

} 

class B extends A { 
@Override 
public void f1(String str) { 
    System.out.println("B.f1(String)"); 
    super.f1(str); 
} 

@Override 
public void f1(int i, String str) { 
    System.out.println("B.f1(int, String)"); 
    super.f1(i, str); 
} 

public static void main(String[] args) { 
A a = new B(); 
    a.f1("Hello"); 
} 
} 
+0

** Câu hỏi này đã hơn 3 năm. ** Bạn chỉ cần đăng một số mã mà không cần bất kỳ lời giải thích nào. Ngoài ra một lỗ hổng trong thiết kế của bạn là lớp 'A' cần phải biết tất cả các lớp con của nó ('B' trong trường hợp đơn giản này), điều này rất khó nếu bạn muốn tạo một lớp con mới vì sau đó bạn phải điều chỉnh lớp' A' cũng thế. –

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