Параметры вложенного типа в Java - PullRequest
9 голосов
/ 09 ноября 2011

Это пример, который я составил для упрощения моего реального кода, поэтому я прошу прощения, если он немного надуманный.То, что я хотел бы сделать, это эффективно получить два параметра типа из одного аргумента вложенного типа.Я почти уверен, что это невозможно, но я подумал, что смогу это сделать.

//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");

Я знаю, что мог бы сделать это, добавив другой параметр типа:

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

но затем я должен добавить избыточность:

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

И в моем случае с реальным миром мои обобщенные элементы могут иногда указываться в предложении Implements, например

public class Bar implements Baz<String>

При необходимости указать этоПараметр второго типа еще более болезненен, потому что кажется, что он бросает детали реализации в мое лицо.То, что говорить «1013 *

Foo<Bar,String>

», когда уже есть отношения между Стрингом и Баром, кажется просто неуравновешенным.Я понимаю, что это Java, так что это идет с территорией, но просто любопытно, было ли решение для этого.

Ответы [ 3 ]

6 голосов
/ 09 ноября 2011

Это невозможно, и я не думаю, что это в любом случае идеально, потому что в вашем существующем классе нет ничего, что требовало бы неизменности.

Foo<T,C extends Collection<T>>

в более общем смысле может быть

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

если единственная причина, по которой стоит T, это разрешить мутацию коллекции.

Обратите внимание: если вас беспокоит необходимость часто указывать два параметра типа, вы можете создать поверхностный подкласс:

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

и вы можете использовать фабричные методы, чтобы избежать необходимости указывать дважды при создании

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

Вы также можете абстрагировать интерфейс в interface, чтобы получить преимущества лаконичных типов, которые вы получаете с DerivedFoo выше.

2 голосов
/ 09 ноября 2011

До Java7 конструкторы не делали вывод типа, обходной путь должен иметь статический метод фабрики. Это больше не нужно. В Java 7 вы можете

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

Относительно T и C, если у нас есть 2 параметра типа с ограничениями между ними, должна быть некоторая степень избыточности. В вашем примере, поскольку один параметр C полностью определяет другой параметр T, избыточность кажется невыносимой. Я не вижу решения.

Но вы, вероятно, чувствуете себя лучше, если параметры типа переупорядочены

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

поэтому мы объявляем String первым; затем дополнительно укажите Baz<String>, что составляет Bar

2 голосов
/ 09 ноября 2011

Почему бы вам не использовать T в качестве единственного параметра типа, например:

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);
}
...