Java generic и типы массивов, не то, что вы думаете (например, массивы из общих типов)
Я пытаюсь указать, что общий класс должен быть массивом или, еще лучше, примитивным массивом. Пока это то, что я получил:
interface Foo<T> {
void process( T data );
}
public class Moo implements Foo<int[]> {
void process( int[] data ) {
// do stuff here
}
}
Это вполне корректный Java-код и работает, потому что примитивные массивы расширяют Object. Обратите внимание, что этот вопрос полностью отличается от всех других общих вопросов Java, которые я продолжаю находить. В этой ситуации люди хотят создать массив из общего типа.
Проблема заключается в том, что тип T может быть тем, что расширяет Object. Я хочу сделать что-то вроде:
<T extends ONLY ARRAYS>
или
<T extends ONLY PRIMITIVE ARRAYS>.
Возможно ли это?
EDIT: конечной целью было бы добавить проверку времени компиляции в передаваемом массиве. Прямо сейчас любой старый объект может быть передан, и он будет компилироваться просто отлично. Ошибка будет обнаружена только во время выполнения, когда выбрано исключение класса. На самом деле это весь смысл Generics в Java, чтобы добавить более сильную проверку типа времени компиляции.
Ответы
Ответ 1
Вы не можете этого сделать. Никакой класс не может расширять массив, поэтому никогда не будет типа, который удовлетворяет общему параметру T extends Object[]
. (Кроме Object[]
, но тогда вы не будете использовать generics.)
Что вы можете сделать, это примерно так:
public interface Foo<T extends Number> {
public void process(T[] data);
}
Но тогда вы можете столкнуться с проблемами производительности с боксом.
Ответ 2
В Java параметры типа могут only быть ограничены отношением подтипа и единственными распространенными супертипами всех массивов Object
, Clonable
и Serializable
. Самое близкое, что вы можете получить, это ограничить Object[]
, который является супертипом всех массивов с не примитивными типами компонентов или, возможно, до Number[]
, который является супертипом Integer[]
, Long[]
,...
Даже если Java поддерживает такое ограничение, как бы вы сделали что-нибудь полезное с этим массивом? Вы не можете читать отдельные элементы, так как вы не можете объявить переменную для хранения результатов и не писать отдельные элементы, поскольку вы не можете записать выражение, которое присваивается элементу массива.
Тем не менее, я бы привязал переменную типа к типу компонента, а не к типу массива:
interface Foo<T extends Whatever> {
void process(T[] data );
}
потому что вы можете обратиться к T[]
, зная T
, но зная, что T extends Object[]
не позволяет напрямую ссылаться на тип компонента.
Изменить: Джеффри правильно указывает, что тип массива не может использоваться в ограничениях типа, т.е. <T extends Whatever[]>
не компилируется, поэтому вам обязательно нужно следовать моему совету объявления <T extends Whatever>
и использовать T[]
для ссылки на тип массива.
Ответ 3
Нет. Нет "интересного" интерфейса и никакого супертипа, но Object существует для массивов примитивов:
public class SOTEST {
public static void main(String[] args) throws Exception {
int[] arr = new int[] {};
Class c = arr.getClass();
for(Class clazz:c.getInterfaces()) {
System.out.println(clazz.getName());
}
System.out.println(c.getSuperclass().toString());
}
}
Ответ 4
Массивы X не имеют иерархии типов. Integer [] не является подклассом Number [].
Чтобы получить то, что вы хотите, используйте тип компонента массива в качестве вашего параметра T и объявите параметры и возвращайте типы как массивы T.