Ограниченный шаблон Java в обратном типе
Я читал в разных местах, включая здесь, что наличие ограниченного шаблона в методе возвращаемого типа - плохая идея. Однако я не могу найти способ избежать этого с помощью моего класса. Я что-то пропустил?
Ситуация выглядит примерно так:
class EnglishReaderOfPublications {
private final Publication<? extends English> publication;
EnglishReaderOfPublications(Publication<? extends English> publication) {
this.publication = publication;
}
void readPublication() {
publication.omNomNom();
}
Publication<? extends English> getPublication() {
return publication;
}
}
В заключение, класс, который я хочу, чтобы иметь возможность использовать любую публикацию, которая в некотором варианте для английского. Класс должен разрешить доступ к публикации извне, но, в идеале, вызывающие элементы getPublication
не хотели бы, чтобы результат был ограниченным подстановочным знаком. Они были бы довольны Publication<English>
.
Есть ли способ обойти это?
Ответы
Ответ 1
Ограниченные подстановочные знаки являются заразными, и именно на них ссылается страница, на которую вы ссылаетесь. Ну, не отрицая этого... но я думаю, я не вижу в этом такой большой проблемы.
Есть много случаев, когда я возвращаю ограниченный шаблон именно потому, что он заразителен. JDK, к лучшему или худшему (я говорю хуже, но что другая коробка для мыла:)) не имеет интерфейсов для коллекций только для чтения. Если я вернусь List<Foo>
, что я не хочу, чтобы люди изменяли (возможно, даже безопасно завернуты в Collections.unmodifiableList
), нет способа объявить это в моей обратной подписи. Как обходной путь для бедных людей, я часто возвращаю List<? extends Foo>
. По-прежнему можно попытаться изменить этот список, удалив элементы или вставив null
, но по крайней мере тот факт, что вы не можете add(new Foo())
, служит напоминанием о том, что этот список, вероятно, доступен только для чтения.
В общем, я думаю, что возвращение чего-то с ограниченным типом возврата вполне разумно, если вы действительно хотите, чтобы сайт вызова имел ограниченный доступ к объекту.
Другим примером может быть потокобезопасная очередь, которую вы передаете различным потокам, где один поток является производителем, а другой - потребителем. Если вы дадите продюсеру Queue<? super Foo>
, то ясно, что вы намереваетесь их вставлять в него предметы (и не брать элементы). Точно так же, если вы дадите потребителю Queue<? extends Foo>
, ясно, что вы намерены взять их (а не поместить элементы).
Ответ 2
Можете ли вы использовать параметр ограниченного типа в объявлении класса?
class EnglishReaderOfPublications<E extends English> { ...
Затем вы можете использовать этот параметр типа везде, где у вас есть параметр подстановки.
Ответ 3
"в идеале, вызывающие getPublication не хотели бы, чтобы результат был ограниченным шаблоном. Они были бы довольны Publication<English>
."
Почему "не хотят" они этого хотят? Будут ли они "счастливы" с помощью Publication<? extends English>
? Вопрос в том, что эти вызывающие лица должны делать с этим объектом Publication. Если все, что они делают, это избавить от этого, тогда Publication<? extends English>
достаточно, и это лучше, потому что оно более общее. Однако, если им нужно вложить в него вещи, вы не можете использовать Publication<? extends English>
.