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

Предположим, у меня есть это:

class test<T>
{
    private T[] elements;
    private int size;
    public test(int size)
    {
        this.size = size;
        elements = new T[this.size];
    }
}

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

Редактировать: Извините, я забыл [] в объявлении элементов.

Ответы [ 7 ]

13 голосов
/ 21 декабря 2008

Проблема в том, что, поскольку компилятор преобразовывает параметр общего типа T в Object (он называется стирание типа ), вы фактически создаете массив Object. Что вы можете сделать, это предоставить Class<T> для функции:

class test<T>
{
    private T[] elements;
    private int size;
    public test(Class<T> type, int size)
    {
        this.size = size;
        elements = (T[]) Array. newInstance(type, size);
    }
}

Вы найдете лучшее объяснение здесь: Анжелика Лангер - Могу ли я создать массив, тип компонента которого является параметром типа?

8 голосов
/ 21 декабря 2008

самая простая альтернатива универсальному массиву - использовать список.

3 голосов
/ 02 мая 2009

Я стараюсь избегать базовых массивов и использую ArrayLists (или подобные Lists ) везде, где это возможно, по множеству причин Два наиболее важных:

  1. Мне не нужна семантика лысого массива. В обозначениях в скобках нет ничего (например, сокращение для арифметики указателей), которые облегчили бы мою жизнь.

  2. Если я использую списки, я настраиваю себя на использование более сложных структур с поддержкой параллелизма по мере необходимости. Например, очень просто заменить ArrayList на CopyOnWriteArrayList .

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

class test<T> {
    /** It's not strictly necessary to make this a List vs. an ArrayList
        You decide what interface you really need to expose internally. */
    private List<T> elements;
    /** This parameter isn't necessary with a List.  You can always call the
        size() method instead. */
    private int size;
    public test(int size) {
        this.size = size;
        elements = new ArrayList<T>();
        // Note that the next line isn't strictly necessary.
        // An ArrayList can be dynamically resized without any real effort on your part.
        elements.ensureCapacity(size); 
    }
}
2 голосов
/ 02 мая 2009

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

Один из них - просто использовать простой массив объектов Object[]. Недостатком является то, что вы потеряете преимущества дженериков и вам придется разыгрывать исходящие из него вещи, что делает код более уродливым. Но так как вы единственный, кто вкладывает в это вещи, то актерский состав всегда должен быть в безопасности. Снаружи не нужно знать, что происходит.

Другие варианты - это своего рода хак. Вы создаете Object[], а затем «приводите» его к T[]. Технически это недопустимо, поскольку Object[] и T[] - это разные типы времени выполнения, и первый не может быть приведен ко второму. Но до тех пор, пока вы не передадите массив вне класса (например, вернете его или что-то еще), это не вызовет никаких проблем, потому что T[] все равно будет стерто до Object[], и на самом деле никакое приведение выполнила. Тогда вы можете воспользоваться преимуществами обобщений в своем классе для упрощения кодирования, но вы должны быть предельно осторожны, чтобы не передавать этот массив любому, кто на самом деле ожидает T[], потому что это не так.

0 голосов
/ 09 августа 2013

Смотрите также этот код:

public static <T> T[] toArray(final List<T> obj) {
    if (obj == null || obj.isEmpty()) {
        return null;
    }
    final T t = obj.get(0);
    final T[] res = (T[]) Array.newInstance(t.getClass(), obj.size());
    for (int i = 0; i < obj.size(); i++) {
        res[i] = obj.get(i);
    }
    return res;
}

Преобразует список объектов любого типа в массив того же типа.

0 голосов
/ 03 мая 2009

Поле размера выглядит избыточным. Вы могли бы просто иметь elements.length вместо размера.

class Test<T> {
    private final T[] elements;
    public test(int size) {
        elements = (T[]) new Object[size];
    }
}

Или вы можете заменить класс Test на ArrayList. то есть вообще бросить класс.

0 голосов
/ 21 декабря 2008

Я могу ошибаться, но ваше заявление кажется странным, если у вас нет:

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