2010-02-14 50 views
5

Tôi có một lớp cơ sở được gọi là Yếu tố. Một số lớp khác (như Label và Image) đều mở rộng lớp này.Các phương pháp được tải quá mức ưu tiên

bây giờ tôi có một lớp điều phối có các phương pháp sau:

public class Dispatcher { 
    public static AbstractPropertyEditor<Label> createEditor(Label e) { 
    ... 
    } 

    public static AbstractPropertyEditor<Element> createEditor(Element e) { 
    ... 
    } 
} 

Nếu bây giờ tôi có một thể hiện của Label (kéo dài Element) và tôi muốn vượt qua nó để createEditor(), tại sao là phương pháp chung nhất (cái thứ hai) được gọi là? Nó sẽ không được bình thường rằng phương pháp cụ thể nhất (createEditor(Label e)) được gọi là?

tôi hoàn toàn cần các phương pháp với Element-param để "bắt" tất cả những lớp học a) thực hiện phần tử nhưng không có phương pháp cụ thể của mình trong lớp dispatching này ..

Tôi đang sử dụng Java 6, làm thế nào để "sửa" này?

Chỉnh sửa: Được rồi, tôi phải thừa nhận nó hoàn toàn không phải về generics. Nhưng đó là nơi tôi gặp nó lần đầu tiên.

cảm ơn và liên quan

+0

Bạn có thể hiện được gán cho một biến kiểu 'Label' không phải' Element'? –

+0

(và không phải 'T mở rộng Element' trong đó' T' xảy ra là 'Nhãn'?) –

Trả lời

6

Tại sao bạn không:

  • làm Element lớp trừu tượng mà cung cấp một mặc định thực hiện createEditor()
  • làm Label ghi đè createEditor().

Vì vậy, bạn sẽ không cần các tiện ích tĩnh và sẽ đạt được mục tiêu của mình.

Nếu bạn cần Element là một giao diện, sau đó:

  • xác định createEditor() như phương pháp Element
  • định nghĩa một giao diện EditorFactory
  • cung cấp DefaultEditorFactoryListEditorFactory
  • sử dụng các nhà máy thích hợp trong người triển khai của Element:

    public Editor createEditor() { 
        editorFactory.createEditor(this); 
    } 
    

nơi bê tông EditorFactory được khởi tạo hoặc trong quá trình khởi hoặc thông qua một số loại dependecy-tiêm.


Theo câu hỏi cụ thể của bạn - tùy thuộc vào loại bạn đã biên dịch ở đó. Nếu bạn gọi createEditor(obj) nó sẽ phụ thuộc cho dù đó là Element obj = .. hay Label obj = ..

+0

hmmmm ... phải suy nghĩ một lúc về hậu quả ý tưởng của việc triển khai createEditor trong Element và các lớp con sẽ có ... trong trường hợp đầu tiên, nó không giống như một ý tưởng tồi. và trong tình huống của tôi, tôi có thể sử dụng nó theo cách đó. Nhưng nếu bạn vẫn muốn những lớp tiện ích tĩnh tách biệt vì những lý do tách biệt? Làm thế nào để Java xác định trong trường hợp của tôi mà phương pháp để gọi? Nó có luôn luôn gọi cái chung nhất? Có cách nào để gọi nó là cái cụ thể nhất không? – Atmocreations

+0

đã cập nhật câu trả lời của tôi. và xem câu trả lời của người khác cũng như cho hành vi chính xác. – Bozho

+0

nhìn thấy nó, thx. vâng ... vấn đề là tôi không thích bỏ thứ đó vào Nhãn ngay trước khi gọi phương thức. Nếu không, tôi có thể trực tiếp tạo ra các phương thức như createLabelEditor (Label l), createImageEditor (Hình i) vv Điều này sẽ lỗi thời phương thức có Element như tham số. – Atmocreations

0

Vì bạn có lẽ thực hiện:

Element element = new Label(); 

Nó được xác định bởi trình biên dịch.

+0

, được xem gián tiếp (gọi các phương thức khác nhau tùy theo tình huống) Tôi đang làm điều này, vâng. Liệu nó có thực sự phụ thuộc vào kiểu khai báo của var 'element' để xác định phương thức nào thực sự được gọi? Không phải là phương pháp với loại "thực" (Label) được gọi?Và nếu không, lý do cho việc này là gì? – Atmocreations

2

Điều này thực sự không liên quan gì đến generics và mọi thứ liên quan đến quá tải phương thức. Trong Java, chữ ký phương thức được gọi được xác định tại thời gian biên dịch, không phải lúc chạy, do đó bạn phải kiểm tra và truyền vào thời gian chạy.

Vì vậy, thay thế này:

Element label = getLabel(); 
AbstractPropertyEditor<?> editor = createEditor(label); 

Với điều này:

Element label = getLabel(); 
AbtractPropertyEditor<?> editor; 
if(label instanceof Label) { 
     editor = createEditor((Label) label); 
} else { 
     editor = createEditor(label); 
} 

Các khác (tiêu chuẩn hơn/tốt hơn) cách để sửa lỗi này là để có createEditor phương pháp (Element) kiểm tra các loại và gọi với một dàn diễn viên đúng phương pháp quá tải cho các loại phụ. Tuy nhiên, bạn sẽ có một vấn đề với các tham số trả về của bạn nếu bạn làm điều đó trên các phương thức như được khai báo.

+0

Cảm ơn bạn đã phản hồi tốt, nhưng tôi muốn tránh 'instanceof' bất cứ khi nào có thể. Vì vậy, đây không phải là một lựa chọn cho tôi. – Atmocreations

+0

@Atmocreations, sau đó tôi đề nghị bạn không sử dụng quá tải phương thức với siêu và phân nhóm dưới dạng tham số. Một mô hình như vậy chắc chắn dẫn đến instanceof và casting. – Yishai

1

Từ Java Language Specification:

Khi một phương pháp được gọi (§15.12), số các đối số thực tế (và bất kỳ đối số kiểu tường minh) và các loại đối số thời gian biên dịch được sử dụng, tại thời điểm biên dịch, đến xác định chữ ký của phương thức sẽ được gọi (§15.12.2). Nếu phương pháp mà là để được gọi là một phương pháp dụ, phương pháp thực tế để được gọi sẽ được xác định lúc chạy thời gian, sử dụng phương pháp động tra cứu (§15.12.4).

+0

thx. nhưng trong khi điều này là hoàn toàn chính xác, nó không giúp tôi với vấn đề hiện tại cũng không giải thích cách java xác định phương pháp thực sự được gọi là ở cuối. – Atmocreations

+0

@Atmocreations: Tôi cầu xin sự khác biệt, nó nêu rõ rằng trong trường hợp các phương thức không thể hiện, phương thức được gọi sẽ là phương thức tương ứng với các kiểu đối số tại thời gian biên dịch. Vì trong trường hợp của bạn là Element được gọi, nó có nghĩa là bạn đang gọi phương thức với một Element tại thời gian biên dịch. – JRL

+0

Vâng ... đúng, xin lỗi. Tôi phải thừa nhận rằng tôi chưa từng thấy nó theo cách đó. – Atmocreations

0

Đây là ví dụ về phương pháp quá tải. Mặc dù đối tượng thực tế trong thời gian chạy là Nhãn chứ không phải là Phần tử, lựa chọn trong đó phương thức quá tải để gọi (nói cách khác, chữ ký của phương thức ) KHÔNG được quyết định động khi chạy. Kiểu tham chiếu (không phải kiểu đối tượng) xác định phương thức nạp chồng nào được gọi!

Ví dụ

public class Car {  
} 

public class Toyota extends Car {  
} 

public class MyCar { 

    public void run(Car c) { 
     System.out.println("Run any Car"); 
    } 

    public void run(Toyota t) { 
     System.out.println("Run Toyota Car"); 
    } 

    public static void main(String[] args) { 
     MyCar myCar = new MyCar(); 

     Car c1 = new Car(); 
     myCar.run(c1); // Output: Run any Car 

     Toyota c2 = new Toyota(); 
     myCar.run(c2); // Output: Run Toyota Car 

     Car c3 = new Toyota(); 
     myCar.run(c3); // Output: Run any Car  
    } 
} 

Vì vậy, trong trường hợp của bạn

Element obj1 = new Label(); 
Dispatcher.createEditor(obj); // Method with Element argument is called 
           // as you are passing Element 

Label obj2 = new Label(); 
Dispatcher.createEditor(obj); // Method with Label argument is called 
           // as you are passing Label 

Ngày lưu ý khác, ghi đè phương pháp gọi trình xảy ra tại thời gian chạy và nó phụ thuộc vào loại đối tượng (hay nói cách khác, các loại của ví dụ thực tế trên heap)

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