2008-11-25 18 views
15

Có thể đưa một đối tượng trong Java vào một loại chung kết hợp không?Tôi nên truyền cho Java chung với nhiều giới hạn như thế nào?

Tôi có một phương pháp như:

public static <T extends Foo & Bar> void doSomething(T object) { 
    //do stuff 
} 

Gọi phương pháp này là không có vấn đề nếu tôi có một lớp mà thực hiện cả hai giao diện (Foo & Bar).

Vấn đề là khi tôi cần gọi phương thức này, đối tượng tôi cần truyền cho nó được nhận là java.lang.Object và tôi cần truyền nó để làm cho trình biên dịch hài lòng. Nhưng tôi không thể tìm ra cách làm cho dàn diễn viên này.

chỉnh sửa:

Vấn đề nằm ở một chức năng như thế này:

public void problemFunction (Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     doSomething((Problematic cast) o); 
    } 
} 

}

Trả lời

12

Thật không may, không có dàn diễn viên pháp lý mà bạn có thể làm để đáp ứng tình trạng này. Phải có một loại duy nhất được biết để triển khai tất cả các giao diện mà bạn cần dưới dạng giới hạn để bạn có thể truyền cho nó. Có thể là loại bạn tạo cho mục đích hoặc một số loại hiện có.

interface Baz extends Foo, Bar { } 

public void caller(Object w) { 
    doSomething((Baz) w); 
} 

Nếu loại khác được biết, giống như Baz, để đáp ứng các giới hạn, bạn có thể kiểm tra đối với những loại hình, và có một chi nhánh tại người gọi của bạn mà các cuộc gọi doSomething với một dàn diễn viên đến các loại. Nó không đẹp.

Bạn cũng có thể sử dụng ủy quyền, tạo lớp học của riêng bạn Baz đáp ứng các giới hạn theo yêu cầu của doSomething. Sau đó, bọc đối tượng bạn được truyền vào một thể hiện của lớp Baz và chuyển trình bao bọc đó tới doSomething.

private static class FooBarAdapter implements Foo, Bar { 
    private final Object adaptee; 
    FooBarAdapter(Object o) { 
    adaptee = (Foo) (Bar) o; 
    } 
    public int flip() { return ((Foo) adaptee).flip(); } 
    public void flop(int x) { ((Foo) adaptee).flop(x); } 
    public void blort() { ((Bar) adaptee).blort(); } 
} 

public void problemFunction (Object o) { 
    doSomething(new FooBarAdapter(o)); 
} 
+0

Ý tưởng tốt. Tôi đã sử dụng nó theo một cách hơi khác. Tôi thích FooBarAdapter để có được các đối tượng với 2 loại khác nhau. Các == có thể được sử dụng để kiểm tra xem đó là cùng một đối tượng (không phải là một). Bằng cách này, họ là một loại kiểm tra thời gian biên dịch. –

+1

Tôi kết hợp mô hình được ủy nhiệm này/đặt tên các lớp bên trong phương thức để "bỏ" một đối tượng mà tôi biết để mở rộng/triển khai một tập hợp các lớp và giao diện có nghĩa là các yêu cầu bị ràng buộc. Xem câu trả lời của Jon: http://stackoverflow.com/a/9514406/910718 –

+0

Và điều này dường như là giới hạn của ngôn ngữ Java vì trong Scala chạy trên cùng một JVM, điều này dễ dàng như o.asInstanceOf [Foo with Bar] –

-1

Cách giải quyết khác, bạn có thể định nghĩa một giao diện khác FooBar mở rộng Foo và Bar và yêu cầu lớp của bạn triển khai. Nó thậm chí không phải là một giao diện cấp cao nhất - bạn có thể khai báo nó tin nếu bạn không muốn lộn xộn lên hoặc cải tạo lại phần còn lại của mã của bạn:

private interface FooBar extends Foo, Bar {} 
public void problemFunction (Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     doSomething((FooBar) o); 
    } 
} 
+1

Tôi tin rằng điều này sẽ không hoạt động vì không có gì đảm bảo rằng o thực sự đã "triển khai FooBar". Tôi không nghĩ Java sẽ giả định nó. – ArtB

+0

@ArtB Câu trả lời cho biết "và có lớp của bạn thực hiện điều đó". – cquezel

7
public static <T extends Foo & Bar> void doSomething(T object) 

này dường như để biểu thị rằng bạn sẽ thực hiện nhiều thao tác trên đối tượng được đề cập.

Tôi cho rằng nếu các hoạt động bạn muốn thực hiện trên đối tượng là khác biệt đủ để được phân cách giữa các giao diện, thì chúng đủ khác biệt để xứng đáng với các phương pháp riêng của chúng.

Có khả năng bạn có thể cấu trúc lại mã này để gọi các phương thức riêng biệt để thực hiện thao tác mong muốn. Điều này có thể sẽ làm cho toàn bộ hoạt động rõ ràng hơn từ quan điểm của khách hàng.

Thay vì:

public void problemFunction (Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     doSomething((Problematic cast) o); 
    } 
} 

Nó trở thành:

public void problemFunction(Object o) { 
    if (o instanceof Foo && o instanceof Bar) { 
     fooifySomething((Foo) o); 
     baratizeSomething((Bar) o); 
    } 
} 
+1

LMAO fooify, điều mới mẻ đối với tôi xD – Goodwine

5

Có thể "up-cast" cho một loại công đoàn, bằng các phương tiện khủng khiếp của mã hóa các loại công đoàn vào tham số kiểu của phương thức; ví dụ của bạn, bạn có thể viết

private <Q extends Foo & Bar> Q upcast(final Object in) { 
    return (Q) in; 
} 

// ... elsewhere... 

if (myObject instanceof Foo && myObject instanceof Bar) { 
    doSomething(upcast(myObject)); 
} 
+0

Cảm ơn bạn. Chỉ phiền toái là nó tạo ra một diễn viên không được kiểm soát. Tuy nhiên tôi đã sử dụng một phiên bản sửa đổi mà có Foo chứ không phải là Object và kiểm tra nó thực hiện Bar và sau đó trả về với các diễn viên như bạn đã làm nếu không ném một ClassCastException. –

14

Java 8 giới thiệu khả năng casting with additional bounds. Bạn có thể truyền một số Object làm class với nhiều số interfaces (hoặc chỉ với số nhiều interfaces).

Vì vậy, đây:

doSomething((Problematic cast) o); 

đơn giản trở nên như thế này:

doSomething((Foo & Bar) o); 
+0

Đọc về công ty gần đây này để cập nhật – pvgoddijn

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