从Java列表中删除基本类型时,为什么不进行自动装箱? [英] Why no autoboxing when removing primitive type from a List in Java?

查看:105
本文介绍了从Java列表中删除基本类型时,为什么不进行自动装箱?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有下面的代码抛出IndexOutOfBoundsException:

 List<Character> list = new ArrayList<>();
 char c  = 'a';
 list.add(c);
 list.remove(c); // gets fixed by passing list.remove((Character)c);

我知道发生这种情况是因为删除时不会发生自动装箱,而在添加元素时会发生自动装箱.我的问题是为什么?在添加charCharacter时可以自动装箱,而在remove方法中却不能,则有什么特别之处?

I know that this happens because autoboxing is not happening while removal and it happens while adding an element. My question is why? What is so special in adding that autoboxing from char to Character is possible while in the remove method it's not?

推荐答案

Java将考虑将原始类型装箱为包装器类型,但前提是它尚未考虑不需要将参数装箱的重载方法.

Java will consider boxing a primitive type to a wrapper type, but only if it hasn't already considered an overloaded method that doesn't need to box the argument.

JLS,该部分15.12.2 ,介绍了按以下方式选择的重载:

The JLS, Section 15.12.2, covers which overload is chosen as follows:

  1. 第一阶段(第15.12.2.2节)执行重载解析,不允许装箱或拆箱转换,也不允许使用可变arity方法调用.如果在此阶段未找到适用的方法,则处理将继续进行到第二阶段.

这可确保由于引入了可变Arity方法,隐式装箱和/或拆箱而导致在Java SE 5.0之前在Java编程语言中有效的所有调用都不会被认为是模棱两可的>.但是,声明可变可变方法(第8.4.1节)可以更改为给定方法方法调用表达式选择的方法,因为可变可变方法在第一阶段被视为固定可变方法.例如,在已经声明了m(Object)的类中声明m(Object ...)导致不再为某些调用表达式(例如m(null))选择m(Object),例如m(Object [] )更具体.

This guarantees that any calls that were valid in the Java programming language before Java SE 5.0 are not considered ambiguous as the result of the introduction of variable arity methods, implicit boxing and/or unboxing. However, the declaration of a variable arity method (§8.4.1) can change the method chosen for a given method method invocation expression, because a variable arity method is treated as a fixed arity method in the first phase. For example, declaring m(Object...) in a class which already declares m(Object) causes m(Object) to no longer be chosen for some invocation expressions (such as m(null)), as m(Object[]) is more specific.

(粗体是我的)

  1. 第二阶段(第15.12.2.3节)在允许装箱和拆箱的同时执行重载解析,但仍排除使用可变arity方法调用.如果在此阶段未找到适用的方法,则处理将继续进行到第三阶段.

这确保了如果通过固定arity方法调用适用方法,则永远不会通过可变arity方法调用选择方法.

  1. 第三阶段(第15.12.2.4节)允许将重载与可变arity方法,装箱和拆箱相结合.

编译器认为没有add的其他重载,可能没有装箱就可能匹配add(Character),因此它考虑在第二阶段装箱并找到其匹配项.

The compiler sees no other overload of add that could possibly match add(Character) without boxing, so it considers boxing in the second phase and finds its match.

但是,编译器确实看到了remove的重载,该重载没有进行装箱匹配,

However, the compiler does see an overload of remove that matches without boxing, remove(int), so the char is widened to an int. The compiler found its method in the first phase, so the second phase was never considered. This forces you, as you have figured out, to cast the char explicitly to a Character to get the proper method matched.

碰巧是在Java 5中引入装箱和拆箱导致该版本之前不存在歧义的情况.如果设计这些方法的名称时考虑了这一点,那么设计人员很可能会使用不同的方法名称,从而避免了重载和此处的歧义.

This happens to be a case where in Java 5, introducing boxing and unboxing causes an ambiguity that didn't exist before that version. If these method names were designed with this in mind, the designers most likely would have used different method names, avoiding overloading and this ambiguity here.

这篇关于从Java列表中删除基本类型时,为什么不进行自动装箱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆