Как я могу сделать этот общий Java-бросок? - PullRequest
9 голосов
/ 24 ноября 2008

Как я могу сделать этот общий java-бросок?

public interface IField {

}


class Field implements IField { // package private class

}

public class Form {
  private List<Field> fields;


  public List<IField> getFields() {
    return this.fields;

  }

}

Оператор return выдает ошибку компилятора (я знаю причину - я прочитал учебник по обобщению), но было бы очень удобно написать такой код.

Если бы я объявил "fields" как List, мне пришлось бы использовать много приведений к Field в других методах класса Form.

Могу ли я заставить этот чертов компилятор изменить его правила и скомпилировать этот оператор возврата?

Заранее спасибо.

Ответы [ 5 ]

17 голосов
/ 24 ноября 2008

Лучшее решение, IMO, состоит в том, чтобы изменить сигнатуру вашего метода для использования ограниченного подстановочного знака:

public List<? extends IField> getFields()

Это позволит вызывающей стороне обрабатывать все, что «выходит» из списка, как IField, но не позволяет вызывающей стороне добавлять что-либо в список (без преобразования или предупреждений), поскольку они не знают, что такое реальный "тип списка.

12 голосов
/ 24 ноября 2008

Как это бывает, вы можете, потому что дженерики Java просто привиты, а не являются частью системы типов.

Вы можете сделать

return (List<IField>)(Object)this.fields;

потому что все List<T> объекты имеют одинаковый базовый тип.

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

5 голосов
/ 24 ноября 2008

Не делай этого.

A List<Field> не является List<IField>. Вы можете попытаться заставить компилятор принять его (я думал, что это невозможно, хотелось бы, чтобы это было невозможно), но это может привести к неприятностям. Компилятор позволит пользователю вводить AnotherField, производный от IField, в заданный список, нарушая ваши инварианты и нарушая безопасность типов, которую предоставляют дженерики. Дальнейшее использование List<Field> прекратится, поскольку извлечение странного элемента завершится неявным приведением к полю, где вы не ожидаете, что это произойдет.

Если вам нужно вернуть List<IField> вместо List<Field>, то я рекомендую создать новый список, заполненный теми же элементами. Если вы можете изменить свой интерфейс, воспользуйтесь решением Jon Skeets .

2 голосов
/ 18 мая 2010

Если вызывающий абонент не должен иметь возможность изменять список:

return Collections.<IField>unmodifiableList(this.fields);
0 голосов
/ 24 ноября 2008

Солнечный свет прав, вы можете просто использовать его.

Еще одно исправление - дважды проверить, действительно ли вам нужен List<Field>, или можете ли вы изменить внутреннюю переменную fields на List<IField>.

Пока вы только когда-либо используете методы в содержимом списка, которые находятся на интерфейсе IField, вы сможете сделать прямой обмен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...