Вот хорошая ловушка, с которой я только что столкнулся. Рассмотрим список целых чисел:
List<Integer> list = new ArrayList<Integer>();
list.add(5);
list.add(6);
list.add(7);
list.add(1);
Любое обоснованное предположение о том, что происходит, когда вы выполняете list.remove(1)
? Как насчет list.remove(new Integer(1))
? Это может вызвать некоторые неприятные ошибки.
Каков правильный способ различения remove(int index)
, который удаляет элемент из данного индекса иremove(Object o)
который удаляет элемент по ссылке при работе со списками целых чисел?
Главное, на что следует обратить внимание, это упомянутое @Nikita - точное сопоставление параметров имеет приоритет над автобоксом .
java
collections
overloading
Ювал Адам
источник
источник
Ответы:
Java всегда вызывает метод, который лучше всего подходит для вашего аргумента. Автобокс и неявное апкастинг выполняются только в том случае, если нет метода, который можно вызвать без приведения / автобокса.
Интерфейс List определяет два метода удаления (обратите внимание на именование аргументов):
remove(Object o)
remove(int index)
Это означает, что
list.remove(1)
удаляет объект в позиции 1 иremove(new Integer(1))
удаляет первое вхождение указанного элемента из этого списка.источник
Integer.valueOf(1)
это лучшая практика, чемnew Integer(1)
. Статический метод может выполнять кэширование и тому подобное, поэтому вы получите лучшую производительность.new Integer(1)
, но я согласен, чтоInteger.valueOf(1)
или(Integer) 1
эквивалентны.Вы можете использовать кастинг
и
Не имеет значения, является ли n целым или целым, метод всегда будет вызывать тот, который вы ожидаете.
Использование
(Integer) n
илиInteger.valueOf(n)
более эффективно, чемnew Integer(n)
в качестве первых двух, может использовать кэш Integer, тогда как последнее всегда будет создавать объект.источник
Я не знаю о «правильном» способе, но предложенный вами способ прекрасно работает:
удаляет элемент в данной позиции и
удаляет данный объект из списка.
Это потому, что VM сначала пытается найти метод, объявленный с точно таким же типом параметра, и только потом пытается выполнить автоматическую коробку.
источник
list.remove(4)
это точное совпадениеlist.remove(int index)
, поэтому оно будет называться. Если вы хотите , чтобы вызовlist.remove(Object)
сделать следующее:list.remove((Integer)4)
.источник
(Integer)
актерский состав, как ты написал выше, кажется мне самым легким подходом.Там нет необходимости угадывать. Первый случай приведет к
List.remove(int)
вызову, и элемент в позиции1
будет удален. Второй случай приведет кList.remove(Integer)
вызову, и элемент, значение которого равно,Integer(1)
будет удален. В обоих случаях компилятор Java выбирает наиболее подходящую перегрузку.Да, здесь есть вероятность путаницы (и ошибок), но это довольно необычный вариант использования.
Когда эти два
List.remove
метода были определены в Java 1.2, перегрузки не были неоднозначными. Проблема возникла только с введением обобщений и автобокс в Java 1.5. В ретроспективе было бы лучше, если бы одному из методов удаления было присвоено другое имя. Но сейчас уже слишком поздно.источник
Обратите внимание, что даже если виртуальная машина не сделала правильно, что она делает, вы все равно могли бы обеспечить правильное поведение, используя тот факт, что
remove(java.lang.Object)
работает с произвольными объектами:источник
equals
метода, в частности (из Javadoc). «Это симметрично: для любых ненулевых ссылочных значений x и y x.equals (y) должен возвращать true тогда и только тогда, когда y.equals ( х) возвращает истину. Как таковой, он не гарантированно работает на всех реализацияхList
, потому что любая реализация List может менять местами x и yx.equals(y)
по желанию, поскольку JavadocObject.equals
говорит, что это должно быть допустимо.Просто мне понравилось следовать предложению #decitrig в принятом ответе.
Это помогло мне. Еще раз спасибо #decitrig за ваш комментарий. Это может помочь для кого-то.
источник
Ну, вот в чем фокус.
Давайте возьмем два примера здесь:
Теперь давайте посмотрим на результат:
Теперь давайте проанализируем вывод:
Когда 3 удаляется из коллекции, он вызывает
remove()
метод коллекции, который принимает вObject o
качестве параметра. Следовательно это удаляет объект3
. Но в объекте arrayList он переопределяется индексом 3 и, следовательно, 4-й элемент удаляется.По той же логике удаления объекта null удаляется в обоих случаях во втором выводе.
Таким образом, чтобы удалить число,
3
являющееся объектом, нам явно нужно будет передать 3 какobject
.И это может быть сделано путем приведения или обтекания с использованием класса обертки
Integer
.Например:
источник