Java не разрешает массивы внутренних классов для общего класса

Я знаю, что вы не можете создать массив родового типа, вместо этого вам нужно прибегнуть к взлому. (Учитывая, что Java поддерживает общие массивы, а не их создание, мне непонятно, почему хак лучше, чем Java, поддерживающий создание общих массивов)

Вместо написания этого

Map.Entry<K, V>[] entries = new Map.Entry<K, V>[numEntries];

вам нужно написать это

@SuppressWarnings("unchecked")
Map.Entry<K, V>[] entries = (Map.Entry<K, V>) new Map.Entry[numEntries];

К сожалению, это не работает, если у вас есть массив вложенного типа общего

public class Outer<E> {
    final Inner[] inners = new Inner[16]; // Generic array creation

    class Inner {
    }
}

Лучшая работа вокруг -

@SuppressWarnings("unchecked")
final Inner[] inners = (Inner[]) Array.newInstance(Inner.class, 16);

Это самое "элегантное" решение?


Я вижу Ошибка создания компиляции Generic Array из внутреннего класса, но решение здесь хуже IMHO.

Ответ 1

Выполните следующие действия:

@SuppressWarnings("unchecked")
final Inner[] inners = (Inner[])new Outer<?>.Inner[16];

В первом примере, эквивалентном вашему первому примеру, было бы new Outer.Inner[16], но это будет изолировать неконтролируемый отбор и избежать необработанного типа.

Ответ 2

Что вам нужно понять, так это то, что ваша ситуация такая же, как в первой описанной вами ситуации.

Inner - нестатический внутренний класс класса Outer, общий класс. Это означает, что Inner входит в область параметра типа, и просто запись Inner коротка для Outer<E>.Inner. т.е. он может не выглядеть, но просто Inner является параметризованным типом, как и Map.Entry<K, V>, поскольку параметр типа E внешнего класса становится неявным параметром типа внутреннего класса. Решение обеих проблем одно и то же.

Ваше решение первой проблемы состояло в том, чтобы создать массив необработанного типа, т.е. new Map.Entry[numEntries];. Какой здесь тип сырья? Не Inner, как мы уже говорили. Вместо этого вам нужно явно указать внешний тип для доступа к необработанному типу: new Outer.Inner[16];. Конечно, вам нужно бросить, чтобы вернуть его в нужный общий тип массива:

(Inner[])new Outer.Inner[16]

Существует еще один способ создания массива общего типа без использования необработанного типа - с использованием подстановочного типа, т.е. new Map.Entry<?, ?>[numEntries];. Эквивалентом для нашего случая будет new Outer<?>.Inner[16];. С приложением:

(Inner[])new Outer<?>.Inner[16]

Ответ 3

Можно ли сделать внутренний класс static?

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

public class Outer<E> {
    final Inner[] inners = new Inner[16]; // works

    static class Inner {
    }
}