2013-07-31 42 views
7

Trong đoạn mã dưới đâyphương pháp chữ ký trong thừa kế

class A { 
    public void v(int... vals) { 
     System.out.println("Super"); 
    } 
} 

class B extends A { 
    @Override 
    public void v(int[] vals) { 
     System.out.println("Sub"); 
    } 
} 

Sau đó, tôi có thể gọi new B().v(1, 2, 3);//print Sub rather than Super đó là vô lý nhưng không làm việc tốt. Nếu tôi thay đổi B để

class B { 
    public void v(int[] vals) { 
     System.out.println("Not extending A"); 
    } 
} 

cuộc gọi đến new B().v(1, 2, 3); sẽ là không hợp lệ. Bạn phải gọi nó là new B().v(new int[]{1, 2, 3});, tại sao?

+0

Một sự hiểu biết đơn giản về kế thừa và quá tải Java có thể giải thích điều này ... Nếu lớp B không mở rộng lớp A, thì lớp B không thể thực hiện phương pháp được viết cụ thể trong lớp A. –

+0

@ MohammadS.what là ma thuật ở đây là phương thức v (int []) trong B thực sự ghi đè phương thức v (int ...) Vì vậy, mặc dù chữ ký của v trong B là v (int []), nó vẫn có thể được gọi bằng cách sử dụng v (1, 2, 3) –

+0

Lưu ý rằng phiên bản đầu tiên của bạn không hoạt động với JDK 7. Bạn đang sử dụng trình biên dịch Java nào? –

Trả lời

7

Trong JDK 1.7, không phải các ví dụ của bạn biên dịch và tôi không tin là nên. Thật dễ dàng để xem tại sao phiên bản thứ hai không - khi B không mở rộng A, không có dấu hiệu của varargs cả, vì vậy không có lý do gì trình biên dịch có thể chuyển đổi danh sách đối số của ba đối số int một đơn int[]. Tình huống thú vị hơn là nơi Blàm mở rộng A.

Trình biên dịch tìm thấy chữ ký của v(int[] vals)không sử dụng varargs. Không có gì trong spec để nói nó nên tìm kiếm chuỗi thừa kế để tìm xem một trong những khai báo khác (có thể có nhiều cái) sử dụng varargs. Thực tế là nó xuất hiện trong phiên bản JDK 1.6 của bạn cho thấy đó là một lỗi trình biên dịch đã được sửa chữa. (Tôi vừa sao chép lỗi trong JDK 1.6.0_39.)

Về cơ bản, nếu bạn muốn có thể gọi B.v() theo cú pháp kiểu biến thể, B.v() phải được khai báo bằng cách sử dụng varargs. Tất nhiên, nếu bạn thay đổi nó để loại thời gian biên dịch là A, mà sẽ làm việc:

A a = new B(); 
a.v(1, 2, 3); 

Hoặc thậm chí (ick):

((A) new B()).v(1, 2, 3); 

Lưu ý rằng nếu bạn biên dịch với -Xlint bạn nhận được cảnh báo về B anyway:

Test.java:14: warning: v(int[]) in B overrides v(int...) in A; overriding method 
is missing '...' 
    public void v(int[] vals) { 
       ^
+1

Tôi đã không nhận được av (1,2,3) một phần? Cái này đến từ đâu? – kosa

+0

@Nambari: Đó là phiên bản của 'v' được khai báo trong' A', sử dụng varags: 'v (int ... vals)' –

+0

Thực ra trong trường hợp đầu tiên, B a = new B(); a.v (1, 2, 3); cũng sẽ hoạt động tốt –

0

Nó không hoạt động vì cách hoạt động.

Nếu phương pháp của bạn là:

foo(int... par) 

foo(new int[]{1, 2, 3}); 
foo(1, 2, 3); 

Cả hai đều là các cuộc gọi phương pháp hợp lệ. Tuy nhiên, nó không hoạt động theo cách khác.

Nếu phương pháp của bạn là:

bar(int[] par) 

bar(new int[]{1, 2, 3}); // Valid 
bar(1, 2, 3); // Invalid! 

Cuộc gọi thứ hai sẽ là không hợp lệ. Nếu phương thức có tham số vararg, nó có thể chấp nhận một mảng; nếu nó có một tham số mảng, nó chỉ có thể chấp nhận một mảng, không phải là một chuỗi các tham số!

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