2011-11-08 39 views
8

Đây là một ví dụ mà tôi tạo ra để đơn giản hóa mã thực sự của mình, vì vậy tôi xin lỗi nếu nó có chút ít giả tạo. Những gì tôi muốn làm là để có hiệu quả có được hai loại tham số trong một đối số kiểu lồng nhau duy nhất. Tôi khá chắc chắn điều này là không thể, nhưng tôi nghĩ rằng tôi sẽ cho nó một shot.Các tham số kiểu lồng nhau trong Java

//Not legal java code 
public class Foo<C extends Collection<T>> { //where T is another type parameter 
    private C coll; 

    public Foo(C coll) { 
     this.coll = coll; 
    } 

    public void add(T elem){ 
     this.coll.add(elem); 
    } 
    //UPDATED TO ADD GETTER 
    /** 
    * I may need to retrieve the collection again, or pass it 
    * on to another function that needs the specific C type 
    */ 
    public C getColl(){ 
     return coll; 
    } 
} 
... 
List<String> strings = new ArrayList<String>(); 
Foo<List<String>> foo = new Foo<List<String>>(strings); 
foo.add("hello"); 

Tôi biết rằng tôi có thể làm điều đó bằng cách thêm một tham số kiểu:

public class Foo<C extends Collection<T>,T> 

nhưng sau đó tôi phải thêm dư thừa:

Foo<List<String>,String> foo = new Foo<List<String>,String>(strings); 

Và trong trường hợp thế giới thực của tôi, đôi khi generics của tôi có thể được chỉ định trong mệnh đề thực hiện như

public class Bar implements Baz<String> 

Phải xác định rằng tham số loại thứ hai thậm chí còn đau hơn nữa, bởi vì nó cảm thấy như nó ném các chi tiết thực hiện trong khuôn mặt của tôi. Phải nói

Foo<Bar,String> 

khi có mối quan hệ giữa Chuỗi và Bar, có vẻ như không phù hợp. Tôi nhận được rằng Java của nó, để đi với lãnh thổ, nhưng chỉ tò mò nếu có một giải pháp cho việc này.

Trả lời

6

Nó không thể và tôi không nghĩ rằng nó lý tưởng anyway bởi vì không có gì trong lớp học hiện tại của bạn yêu cầu bất biến.

Foo<T,C extends Collection<T>> 

tổng quát hơn có thể là

Foo<T,C extends Collection<? super T>> 

nếu lý do duy nhất để có T là cho phép đột biến của bộ sưu tập.

Lưu ý, nếu bạn quan tâm về việc phải xác định hai tham số kiểu thường xuyên, bạn có thể tạo một lớp con nông:

class DerivedFoo<T> extends Foo<Collection<T>,T> 

và bạn có thể sử dụng phương pháp nhà máy để tránh phải đúp chỉ định lúc tạo

public static <T> Foo<Collection<T>,T> fromCollection(Collection<T> c) 

bạn cũng có thể trừu tượng giao diện vào một interface để có được những lợi ích của các loại súc tích mà bạn nhận được với DerivedFoo trên.

+0

Ý tưởng phương pháp nhà máy là thú vị, nhưng nó vẫn làm phiền tôi rằng loại được chỉ định hai lần mặc dù mã của tôi cho rằng chúng luôn giống nhau. –

+0

@RusselLeggett, ok, vì vậy bạn cần bất biến sau đó, không có 'Bộ sưu tập '? Vâng. Đó là một nỗi đau. Lời khuyên của tôi là giải quyết sự phức tạp trong thư viện của bạn và cố gắng hiển thị API terse bằng cách có các nhà máy có kiểu trả về là 'interface Foo mở rộng ComplicatedFoo , T>' để khách hàng chỉ có thể sử dụng phiên bản tham số đơn. –

2

Tại sao bạn sẽ không chỉ cần sử dụng T như tham số kiểu duy nhất của bạn, như trong:

public class Foo<T> { //where T is another type parameter 
private Collection<T> coll; 

public Foo(Collection<T> coll) { 
    this.coll = coll; 
} 

public void add(T elem){ 
    this.coll.add(elem); 
} 
+0

Tôi tò mò muốn biết tại sao điều này cũng không phải là giải pháp. – ty1824

+3

Như tôi đã nói, đó là một ví dụ giả tạo, nhưng điều gì sẽ xảy ra nếu loại bộ sưu tập đó cũng quan trọng. Nó có thể là một danh sách hoặc một bộ hoặc một TreeList. Hãy nói rằng tôi đã thêm một getter để lấy bộ sưu tập một lần nữa - loại sẽ là vấn đề. –

2

Trước Java7, nhà thầu không làm kiểu suy luận, thực hiện giải pháp là phải có một phương thức tĩnh. Điều đó không còn cần thiết nữa. Trong Java 7 bạn có thể

Foo<List<String>,String> foo = new Foo<>(strings); 

Về TC, nếu chúng ta có 2 thông số loại với các ràng buộc giữa họ, có phải có một số mức độ dự phòng. Trong ví dụ của bạn, vì một tham số C hoàn toàn ra lệnh cho tham số khác T, sự thừa có vẻ không thể chịu nổi. Tôi không thấy một giải pháp.

Nhưng có lẽ bạn có thể cảm thấy tốt hơn nếu các thông số loại được sắp xếp lại

Foo<String,Bar> foo = new Foo<>(bar); 

vì vậy chúng tôi tuyên bố String đầu tiên; sau đó cung cấp thêm Baz<String>Bar

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