2009-02-05 20 views
24

У меня есть метод, как это:Java: массив примитивных типов данных не Autobox

public static <T> boolean isMemberOf(T item, T[] set) 
{ 
    for (T t : set) { 
     if (t.equals(item)) { 
      return true; 
     } 
    } 
    return false; 
} 

Теперь я пытаюсь вызвать этот метод с использованием char для T:

char ch = 'a'; 
char[] chars = new char[] { 'a', 'b', 'c' }; 
boolean member = isMemberOf(ch, chars); 

Это Безразлично» т работы. Я ожидал бы char и char[], чтобы получить autoboxed до Character и Character[], но это, похоже, не происходит.

Любые идеи?

ответ

33

Не существует автобоксинга для массивов, только для примитивов. Я считаю, что это твоя проблема.

+4

Да, это проблема. Это кажется мне так разбито ... или, по крайней мере, противоречивым. –

+5

И ограничение Java, ИМХО. –

+0

Мне лично не нравится автобоксинг, так как это сравнительно дорогая операция, которую я хотел бы предотвратить, если это действительно необходимо. – Eddie

12

Зачем нужен char[] до Character[]? Массивы всегда ссылочные типы, поэтому не требуется бокс.

Кроме того, это было бы ужасно дорого - это было бы связано с созданием нового массива, а затем по боксу каждый символ по очереди. Хлоп!

+7

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

1

Это, по-видимому, по дизайну, чтобы избежать такой дорогостоящей операции автобоксинга и потому, что дженерики должны быть обратно совместимы с существующим байт-кодом Java.

См., Например, this article и this bug.

1

Массивы - это тип реализации на низком уровне. char[] будет смежной областью памяти с двухбайтовыми символами. Character[] будет непрерывной областью памяти с четырьмя или восемью байтовыми ссылками. Вы не можете получить Character[], чтобы обернуть char []. Однако List<Character> может обернуть char[].

Массивы ссылок обычно не являются хорошей идеей, если вы не пишете низкоуровневый код. Вы можете, если хотите, написать или получить эквивалент java.util.Arrays.asList.

0

Более простой способ сделать это

char ch = 'a'; 
String chars = "abc"; 
boolean member = chars.indexOf(ch) >= 0; 
+0

Правда, но я надеялся создать метод, который мог бы использовать с любым типом. –

2

Правильно, нет Autoboxing для массивов (что приводит к странности в таких случаях, как int[] ints; ...; Arrays.asList(ints) - asList возвращает список, содержащий один объект, массив)

Вот простая утилита для размещения массива.

public static Integer[] boxedArray(int[] array) { 
    Integer[] result = new Integer[array.length]; 
    for (int i = 0; i < array.length; i++) 
     result[i] = array[i]; 
    return result; 
} 

Для каждого примитивного типа вам понадобится другая версия.

3

Вы можете использовать отражение, чтобы получить метод, который работает для всех типов массивов, но вы потеряете безопасность типа, поэтому это, вероятно, не то, что вы хотите.

import java.lang.reflect.Array 
public static boolean isMemberOfArray(Object item, Object array) 
{ 
    int n = Array.getLength(array) 
    for (int i = 0; i < n; i++) { 
     if (Array.get(array, i).equals(item)) { 
      return true; 
     } 
    } 
    return false; 
} 
1

Как уже упоминалось, для массивов примитивов нет автобоксинга. Если вы хотите использовать свой метод с примитивными массивами, вам нужно будет обеспечить перегруз для каждого примитивного типа. Кажется, это стандартный способ делать вещи в библиотеках классов. См., Например, перегрузки в java.util.Arrays.

1

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

Существует нет autoboxing для массивов, но есть autoboxing для varargs. Так что, если вы объявите свой метод как (с тем же телом):

public static <T> boolean isMemberOf(T item, T ... set) 

, то вы можете написать

isMemberOf('a', 'a', 'b', 'c'); 

Лично я предпочитаю использовать гуавы Google, где вы можете написать что-то вроде

char ch = 'a'; 
char[] chars = new char[] { 'a', 'b', 'c' }; 
boolean member = isMemberOf(ch, Chars.asList(chars).toArray(new Character[0])); 

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

Chars.contains(chars, ch); 

or 

ImmutableSet.of('a', 'b', 'c').contains('a') 
1

Введите Java 8 и пусть primArray быть идентификатором типа PrimType[], то вы можете сделать следующее:
BoxedType[] boxedArray = IntStream.range(0, primArray.length).mapToObj(i -> primArray[i]).toArray(BoxedType[] :: new);

Смежные вопросы