为什么 ArrayList.remove(char) 自动装箱失败?它将 char 视为 int

lik*_*udo 1 java java-8

我真的很困惑为什么 ArrayList.remove() 会导致堆栈溢出:D

Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 98 out of bounds for length 3
Run Code Online (Sandbox Code Playgroud)

但这不是“C”。char 在语义上更接近 Character 而不是 int。

我的代码(将字符串 s 转换为 t 的最少步骤数):

public class Solution {

    public int minSteps(String s, String t) {
        ArrayList<Character> list = new ArrayList<Character>();
        for (char c : t.toCharArray()) {
            list.add(c);
        }
        System.out.println(list.toString());

        for (char c : s.toCharArray()) {
            System.out.println("trying to remove " + c);
            list.remove(c);
            System.out.println(" result: " + list);
        }
        return list.size();
    }

    public static void main(String[] args) {
        Solution sol = new Solution();
        String s = "bab";
        String t = "aba";
        System.out.println("minSteps: s " + sol.minSteps(s, t));
    }

    public Solution() {
    }
}
Run Code Online (Sandbox Code Playgroud)

控制台输出是

[a, b, a]
trying to remove b
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 98 out of bounds for length 3
    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
    at java.base/java.util.Objects.checkIndex(Objects.java:373)
    at java.base/java.util.ArrayList.remove(ArrayList.java:502)
    at com.sandbox.Solution.minSteps(Solution.java:25)
    at com.sandbox.Solution.main(Solution.java:35)
Run Code Online (Sandbox Code Playgroud)

奇怪的是当我尝试做

boolean b = list.remove(c);
Run Code Online (Sandbox Code Playgroud)

它不会编译!

Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - incompatible types: java.lang.Character cannot be converted to boolean
    at com.sandbox.Solution.minSteps(Solution.java:25)
    at com.sandbox.Solution.main(Solution.java:35)
Run Code Online (Sandbox Code Playgroud)

当我将 c 显式转换为 Character 时,它会起作用。这告诉我自动装箱在这里不起作用!

    boolean b = list.remove(Character.valueOf(c));

[a, b, a]
trying to remove b
 result: [a, a]
trying to remove a
 result: [a]
trying to remove b
 result: [a]
minSteps: s 1
Run Code Online (Sandbox Code Playgroud)

And*_*eas 5

List有2remove种方法:

remove(c)可以通过将char值扩大为 anint或将char值自动装箱为 a来调用它们中的任何一个Character

出于向后兼容性的原因,编译器总是喜欢简单的加宽而不是自动装箱,因此编译器选择进行调用remove((int) c)

要强制它调用另一个方法,请执行以下操作之一:

如果您不喜欢remove通话中的额外内容,您也可以执行以下操作之一:

  • @likejudo 这记录在 *Java 语言规范*,部分 [15.12.2。编译时步骤 2:确定方法签名](https://docs.oracle.com/javase/specs/jls/se13/html/jls-15.html#jls-15.12.2):阶段 1:尝试查找不使用自动装箱的方法。第 2 阶段:如果尚未找到方法,则尝试使用自动装箱来查找方法。--- 在重载之间进行选择是 Java 的全局事务,而不是特定于这 2 个方法,因此当然没有针对该方法进行记录。 (2认同)
  • @likejudo 不符合 **Java 语言规范** 定义的 **确定方法签名的规则**,我已经给出了该链接。这些规则是*语言设计者*决定的,并且出于**向后兼容性的原因**,他们决定*加宽*胜过*自动装箱*,正如答案中已经说明的那样。 (2认同)
  • @likejudo 我还说过,在之前的评论中,不知何故被删除了。--- 我不确定*“这不是'C'”*与任何事情有什么关系,但你是对的:这是**Java**,而不是C,我们都知道这一点,因为你在问题中标记为“java”。 (2认同)