Как вернуть правильный тип списка? - PullRequest
4 голосов
/ 28 января 2012

Если у меня есть такой метод (для простоты предположим целые числа):

public static List<Integer> doSomething(List<Integer> list) {
   // logic here  
}

, и мне нужно для своей обработки создать внутренне новый список , который я создам и каким-то образомзаполнить и вернуться к вызывающей стороне, как я могу это сделать, поскольку я не знаю, в какой тип списка передавался вызывающий абонент?

Я не хочу возвращать List другого типа, который был передан вызывающим абонентом.

Например, если вызывающий абонент передал LinkedList, а я нет хочу вернуть ArrayList.

Как лучше всего решить эту проблему?

Ответы [ 5 ]

7 голосов
/ 28 января 2012

Не следует привязывать свою реализацию к конкретной реализации List, идея использования интерфейса заключается в том, что извне не должно иметь значения, какой конкретный класс вы создаете, если он соответствует List интерфейс.

РЕДАКТИРОВАТЬ:

В любом случае, вот один из возможных способов:

* * 1010

Как видно на консоли, копии являются экземплярами того же класса, что и исходный список.

4 голосов
/ 28 января 2012

Если вы можете использовать только один из этих двух типов вывода, тогда вы можете сделать

if (inputList instanceof RandomAccess) {
  // use an ArrayList
} else {
  // use a LinkedList.
}

Интерфейс RandomAccess предназначен для указания того, что реализация позволяетO (1) get операций.

Маркерный интерфейс, используемый List реализациями для указания того, что они поддерживают быстрый (обычно постоянное время) произвольный доступ.Основная цель этого интерфейса - позволить универсальным алгоритмам изменять свое поведение для обеспечения хорошей производительности при применении к спискам произвольного или последовательного доступа.

Благодаря этому ваши API-интерфейсы позволяют клиентам защищать свои входные данные.,Они могут передать результат Collections.unmodifiableList(...) и быть уверенным, что он не изменен другим кодом.

Если вы действительно знаете, что вход является изменяемым списком, вы можете clone() список, затем clear() это.И ArrayList, и LinkedList имеют публичные clone() методы, к которым можно обращаться рефлексивно.

1 голос
/ 28 января 2012

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

public static void doSomething(List<Integer> dest, List<Integer> src) {
0 голосов
/ 28 января 2012

Если вы действительно, действительно заботитесь о том, какой объект появляется, я бы включил его в качестве параметра метода, например:

<T extends List<Integer>> T doSomething(Class<T> returnType,List<Integer> v)
    throws Exception
{
    // constructors for your return will be tricky :)
    // returnType.newInstance() will probably work.
    T result = returnType.newInstance();
    result.add(86); result.add(99);
    return result;
}
0 голосов
/ 28 января 2012

Вы можете использовать Class.newInstance для создания списка переданных типов:

public static List<Integer> doSomething(List<Integer> list)
{
    List<Integer> newList = null;
    try
    {
        newList = list.getClass().newInstance();
    }
    catch(InstantiationException e)
    {
        throw new RuntimeException(e);
    }
    catch(IllegalAccessException e)
    {       
        throw new RuntimeException(e);
    }

    //Logic here

    return newList;
}

@Test
public void test()
{       
    List<Integer> testList = new ArrayList<Integer>();

    List<Integer> resultList = doSomething(testList);
    Assert.assertEquals(testList.getClass(), resultList.getClass());
    Assert.assertNotSame(LinkedList.class, resultList.getClass());

    testList = new LinkedList<Integer>();

    resultList = doSomething(testList);
    Assert.assertEquals(testList.getClass(), resultList.getClass());
    Assert.assertNotSame(ArrayList.class, resultList.getClass());       
}
...