Ява общий вопрос об интерфейсах - PullRequest
3 голосов
/ 19 февраля 2010

учитывая, что у меня есть метод, который получает список, переданный в качестве параметра. В этом методе я хочу использовать, например, специфическую функцию ArrayList в этом списке (скажем, trimToSize ()). Каков общий подход к решению такой проблемы? Вот два примера:
Первый подход (я не думаю, что это хорошо)

private void doSomething(final List<T> list) {
  // ... do something
  ((ArrayList<T>) list).trimToSize();
  // ... do something
}

Второй подход (я думаю, что этот лучше)

private void doSomething2(final List<T> list) {
final List<T> myList = new ArrayList<T>();
// Collections.copy(myList, list); or
myList.addAll(list);
((ArrayList<T>) myList).trimToSize();
//..do something
}

Мне любопытно, что является лучшим решением для такой проблемы.

Ответы [ 8 ]

12 голосов
/ 19 февраля 2010

Хорошо, предпочтительный вариант - просто написать метод, чтобы взять ArrayList в первую очередь.Если вам нужна ArrayList особая функциональность, метод не имеет смысла принимать List.Передайте ответственность за обеспечение того, что параметр имеет правильный тип для вызывающей стороны и не возитесь с ним внутри метода.

6 голосов
/ 19 февраля 2010

Почему бы просто не объявить метод как private void doSomething(final ArrayList<T> list), если вы хотите использовать только ArrayList в качестве параметра?

3 голосов
/ 19 февраля 2010

Если вы принимаете какой-либо объект, реализующий интерфейс List, ваша функция должна вызывать только методы, реализованные из интерфейса.

Если вы хотите вызывать функции из класса ArrayList, используйте ArrayList в качестве параметра. Гораздо безопаснее, чем любой из ваших вариантов.

2 голосов
/ 19 февраля 2010

Как насчет

private void doSomething(final List<T> list) {
    final ArrayList<T> arrayList;
    if (list instanceof ArrayList) {
        arrayList = (ArrayList<T>) list;
    } else {
        arrayList = new ArrayList<T>(list);
    }
            ...
    arrayList.trimToSize();
}

Конечно, я согласен с Чинмай Канчи: для частного метода нет смысла принимать более общий тип, чем необходимо.Мой подход возможен только в том случае, если он не вызывает проблем при изменении данного списка.

2 голосов
/ 19 февраля 2010

Первый показанный вами вариант работает только для ArrayLists, поэтому он не подходит, если вы хотите поддерживать любой тип List. Если вы хотите поддерживать любой тип List, вы должны преобразовать (не разыграть) его в ArrayList.

Я думаю, что может быть некоторая путаница, потому что List и ArrayList так тесно связаны (по наследству). Это только совпадение, что тип параметра и класс, для которого мы должны вызвать функцию, связаны таким образом.

Если немного абстрагироваться от требований:

  1. Нам нужно воздействовать на ряд значений
  2. Нам нужно использовать trimToSize () на ряд значений.

Если бы значения приходили в виде массива, не могло быть и речи, кроме как создать новый ArrayList со значениями из массива и затем использовать trimToSize () , потому что приведение не было бы вариантом , Просто не повезло, что метод, который нам нужен trimToSize () , находится в подклассе List, и автор хочет передать значения как List.

2 голосов
/ 19 февраля 2010

Во-вторых, у нас огромные накладные расходы с большими списками, но это безопаснее. Я бы пошел на первое, но с проверкой, является ли предоставленный список ArrayList, а затем сделать приведение.

У вас должны быть веские причины не принимать ArrayList в качестве параметра.

1 голос
/ 19 февраля 2010

Ваш первый метод изменяет List, переданный методу, а другой - нет. Два метода несопоставимы.

0 голосов
/ 19 февраля 2010

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

Например, если 5 других методов вызывают этот метод с потенциально разными типами List, используйте второй вариант и централизуйте преобразование в 1 метод (вы даже можете добавить проверку на тип и не преобразовывать, если хотите). Если ваш класс в любом случае имеет дело только с ArrayList внутренне, и вы знаете, что именно так оно и будет при вызове, объявите его как ArrayList и упростите себе жизнь.

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