Ответ 1
Нет никаких автобоксинга для массивов, только для примитивов. Я считаю, что это твоя проблема.
У меня есть такой способ:
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[]
, но это, похоже, не происходит.
Любые идеи?
Нет никаких автобоксинга для массивов, только для примитивов. Я считаю, что это твоя проблема.
Почему char[]
был помещен в поле Character[]
? Массивы всегда являются ссылочными типами, поэтому бокс не требуется.
Кроме того, это было бы ужасно дорого - это включало бы создание нового массива, а затем по боксу каждый char по очереди. Хлоп!
Вы можете использовать отражение, чтобы получить метод, который работает для всех типов массивов, но вы потеряете безопасность типа, поэтому это, вероятно, не то, что вы хотите.
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;
}
Правильно, нет автобоксинга для массивов (что приводит к странности в таких случаях, как 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;
}
Разумеется, вам понадобится другая версия для каждого примитивного типа.
Это, по-видимому, по дизайну, чтобы избежать такой дорогостоящей операции автобоксинга и потому, что дженерики должны быть обратно совместимы с существующим байт-кодом Java.
Смотрите эту статью и эту ошибку, например.
Массивы представляют собой тип реализации на уровне низкого уровня. char[]
будет смежной областью памяти с двухбайтовыми символами. Character[]
будет смежной областью памяти с четырьмя или восьмибайтовыми ссылками. Вы не можете получить Character[]
для обертывания char []. Однако List<Character>
может обернуть char[]
.
Массивы ссылок обычно не являются хорошей идеей, если вы не пишете низкоуровневый код. Вы можете, если хотите, написать или получить эквивалент java.util.Arrays.asList
.
Как уже упоминалось, для массивов примитивов нет автобоксинга. Если вы хотите использовать свой метод с примитивными массивами, вам нужно будет обеспечить перегруз для каждого примитивного типа. Кажется, это стандартный способ делать вещи в библиотеках классов. См. Перегрузки в java.util.Arrays, например.
Во-первых, я старался избегать массивов столько, сколько вы можете, вместо этого используйте списки.
Нет автобоксинга для массивов, но для varargs существует автобоксинг. Поэтому, если вы объявите свой метод как (с тем же телом):
public static <T> boolean isMemberOf(T item, T ... set)
тогда вы можете написать
isMemberOf('a', 'a', 'b', 'c');
Лично я предпочитаю использовать google guava, где вы можете писать такие вещи, как
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')
Введите Java 8 и пусть primArray
будет идентификатором типа PrimType[]
, тогда вы можете сделать следующее:
BoxedType[] boxedArray = IntStream.range(0, primArray.length).mapToObj(i -> primArray[i]).toArray(BoxedType[] :: new);
Более простой способ сделать это -
char ch = 'a';
String chars = "abc";
boolean member = chars.indexOf(ch) >= 0;