2012-01-23 26 views
25

Chỉ bằng thử nghiệm, tôi phát hiện ra rằng các phương thức không tĩnh Java ghi đè tất cả các phương thức có cùng tên trong phạm vi ngay cả ở ngữ cảnh tĩnh. Ngay cả khi không cho phép quá tải tham số. Giống nhưNhập Java tĩnh

import java.util.Arrays;  
import static java.util.Arrays.toString; 

public class A { 
    public static void bar(Object... args) { 
     Arrays.toString(args); 
     toString(args);  //toString() in java.lang.Object cannot be applied to (java.lang.Object[]) 
    } 
} 

Tôi không thể tìm thấy bất kỳ điều gì về điều này trong thông số kỹ thuật. Đây có phải là một lỗi? Nếu không, có lý do gì để thực hiện ngôn ngữ như vậy không?

UPD: Java 6 không biên dịch ví dụ này. Câu hỏi đặt ra là - tại sao?

+0

Dường như nó đang ám chỉ đối tượng của siêu đối tượng 'toString()' –

+2

IMHO, toàn bộ chức năng nhập tĩnh là một khái niệm không tốt, gây ô nhiễm không gian tên và khả năng đọc mã sai. Đừng lười biếng, không quá khó để gõ lớp/giao diện kèm theo của một hàm tĩnh, chúng ta có các IDE cho nó. Cố gắng tránh sử dụng nhập tĩnh. – buc

+0

@Jigar Joshi, Nó seams như vậy. Nhưng tôi không thể tìm thấy bất cứ điều gì về. Và hơn nữa, chúng ta không thể gọi 'Object.toString' từ ngữ cảnh tĩnh nên tôi không thấy bất kỳ logic nào trong hành vi này. –

Trả lời

21

Câu trả lời rất đơn giản mặc dù nó không làm thay đổi thực tế rằng hành vi là rất unintuitive:

Khi giải quyết phương pháp này được gọi là điều đầu tiên trình biên dịch làm là tìm ra phạm vi bao quanh nhỏ nhất mà có một phương pháp tên đúng. Chỉ sau đó đến những thứ khác như độ phân giải quá tải và đồng trong trò chơi.

Bây giờ những gì đang xảy ra ở đây là phạm vi bao quanh nhỏ nhất có chứa phương pháp toString() là loại A kế thừa từ Object. Do đó chúng tôi dừng lại ở đó và không tìm kiếm xa hơn. Đáng buồn thay, trình biên dịch cố gắng tìm ra sự phù hợp tốt nhất của các phương thức trong phạm vi cho trước và thông báo rằng nó không thể gọi bất kỳ phương thức nào và đưa ra một lỗi.

Có nghĩa bao giờ tĩnh nhập phương pháp với một tên tuổi khá giống với một phương pháp trong Object, vì phương pháp mà là một cách tự nhiên trong phạm vi được ưu tiên hơn nhập khẩu tĩnh (JLS mô tả phương pháp shadowing một cách chi tiết, nhưng đối với này vấn đề tôi nghĩ đơn giản hơn nhiều là chỉ cần nhớ điều đó).

Chỉnh sửa: @alf vui lòng gửi phần bên phải của JLS là describes the method invocation cho những người muốn toàn bộ hình ảnh. Nó khá phức tạp, nhưng sau đó vấn đề không phải là đơn giản, vì vậy đó là để được mong đợi.

+4

Liên kết JLS, nếu bạn cần nó - http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.1 – alf

+0

@alf Cảm ơn, điều đó đã giúp bạn có được câu trả lời tốt hơn nhiều . Tôi đã tự mình thêm vào nếu tôi biết nơi tìm mô tả cho nó trong JLS. – Voo

4

Nó không phải là ghi đè. Nếu nó đã hoạt động, this.toString() sẽ vẫn truy cập phương thức A thay vì Arrays.toString như trường hợp nếu ghi đè đã xảy ra.

Các language specification giải thích rằng hàng nhập khẩu tĩnh chỉ ảnh hưởng đến việc giải quyết các static phương pháp và các loại:

Một single-tĩnh-nhập khẩu khai d trong một đơn vị biên dịch c gói p rằng nhập khẩu một lĩnh vực tên n bóng tối sự khai báo bất kỳ trường tĩnh có tên n nào được nhập khẩu bởi một khai báo tĩnh-theo-yêu cầu trong c, trong suốt c.

Một khai báo đơn-nhập d trong đơn vị biên dịch c của gói p nhập khẩu một phương thức có tên là n với chữ ký s bóng khai báo bất kỳ phương thức tĩnh nào có tên n với chữ ký s được nhập bằng tĩnh khai báo theo yêu cầu trong c, trong suốt c.

Một single-tĩnh-nhập khẩu khai d trong một đơn vị biên dịch c gói p rằng nhập khẩu một loại tên n bóng tối tờ khai của:

  • bất kỳ tĩnh loại tên n nhập khẩu của một tĩnh-nhập khẩu khai báo theo yêu cầu trong c.
  • bất kỳ loại cấp cao nhất (§7.6) có tên n được khai báo trong một đơn vị biên dịch khác (§7.3) của p.
  • bất kỳ loại có tên n được nhập bằng khai báo kiểu nhập-theo-yêu cầu (§7.5.2) trong c. trong suốt c.

Nhập tĩnh không làm bóng các phương pháp không tĩnh hoặc kiểu bên trong.

Vì vậy, toString không làm mờ phương pháp không tĩnh. Vì tên toString có thể tham chiếu đến phương pháp không tĩnh của A, nó không thể tham chiếu phương thức staticArrays và do đó toString liên kết với phương thức duy nhất có tên toString có sẵn trong phạm vi, là String toString(). Phương thức đó không thể lấy bất kỳ đối số nào để bạn nhận được một lỗi biên dịch.

Section 15.12.1 giải thích độ phân giải của phương pháp và sẽ phải được viết lại hoàn toàn để cho phép che khuất tên phương thức không khả dụng trong các phương thức static nhưng không nằm trong phương thức member.

Tôi đoán là các nhà thiết kế ngôn ngữ muốn duy trì quy tắc phân giải phương pháp đơn giản, có nghĩa là cùng một tên có nghĩa là nó xuất hiện trong phương thức static hay không và điều duy nhất thay đổi là có sẵn.

+0

Ngoại trừ việc phương thức 'bar' là tĩnh, không có cá thể nào để gọi' toString() 'khi – chrisbunney

+0

@StasKurilin, được chỉnh sửa. –

+2

@StasKurilin [mệnh. 6.3.1] (http://java.sun.com/docs/books/jls/third_edition/html/names.html#34133) giải thích rõ ràng hơn. Nó nói rằng việc khai báo phương thức instance 'Object.toString()' shadows * bất kỳ phương thức nào khác * trong phạm vi của nó. Điều này bao gồm nhập tĩnh cho 'Arrays.toString (Object [])'. Điều này có nghĩa rằng, hiệu quả, nhập khẩu tĩnh có * không có hiệu lực * - trình biên dịch thậm chí sẽ không xem xét nó để giải quyết cuộc gọi phương thức. – millimoose

0

Tôi không nghĩ rằng đó là lỗi hoặc điều gì đó khác với nhập bình thường. Ví dụ, trong trường hợp nhập khẩu bình thường, nếu bạn có một lớp riêng với cùng tên như đã nhập, lớp đã nhập sẽ không được phản ánh.

1

Nếu bạn cố gắng sau tương tự tìm mã sau đó bạn sẽ không nhận được bất kỳ lỗi biên dịch

import static java.util.Arrays.sort; 
public class StaticImport { 
    public void bar(int... args) { 
     sort(args); // will call Array.sort 
    } 
} 

Lý do này biên soạn và bạn không là toString() (hoặc bất kỳ phương pháp khác quy định tại class Object) vẫn bị scoped đối với class Object vì Object là cha của class của bạn. Do đó khi trình biên dịch tìm thấy chữ ký phù hợp của các phương thức đó từ lớp Object thì nó cho phép lỗi trình biên dịch. Trong ví dụ của tôi kể từ lớp Object không có phương thức sort(int[]) do đó trình biên dịch phù hợp đúng với phương thức nhập tĩnh .