java - “redundant cast to java.lang.Object”警告需要强制转换

标签 java casting compiler-warnings compiler-bug ambiguous-call

考虑这个Minimal, Reproducible Example :

interface Code {
    static void main(String[] args) {
        symbol(
            String.valueOf(
                true ? 'a' :
                true ? 'b' :
                true ? 'c' :
                fail()
            )
        );
    }
    private static void symbol(String symbol) {
        System.out.println(symbol);
    }
    private static <R> R fail() {
        throw null;
    }
}
(true接近最小,是一个有用的 boolean 表达式的代表。我们可以忽略第一个? :(在实际代码中,有很多)。)
这“显然”给出了错误。
4: reference to valueOf is ambiguous
  both method valueOf(java.lang.Object) in java.lang.String and method valueOf(char) in java.lang.String match
好,让我们修复它。这是我想要的String.valueOf(Object)重载-我稍后可能想要添加:
            true ? "sss" :
(实际上,我之前确实有类似的东西,但是现在删除了该功能。)
        String.valueOf((Object)(
            true ? 'a' :
            fail()
        ))
这给出了警告:
4: redundant cast to java.lang.Object
这是编译器中的错误警告或错误吗?如何解决该错误,使代码合理且没有警告或错误?
(编辑:我对MRE进行了些微更改。throws Throwable来自template。实际代码确实使用文字字符*和String.valueOf,而其他地方使用了String.valueOf(char)重载,因此toString()有问题(哦Java!)。该代码避免了全局操作状态,例如System.outsymbolfail在不同的类中。“switch”是不可枚举的类型。fail是类似assert方法的伴侣,所以这就是为什么它抛出(未经检查的非null)内部异常。
不相关的是,我实际上是如何重新排列代码的,因此其中也包含一些文字字符串。否则,我将使用与Object.class.cast等效的毫无意义的(Object)。我真正想知道的是:wtf?
*实际上,真正的真实代码会通过一种词法分析器针对另一种语言进行处理,这种语言无法区分文字字符,字符串,各种数字, boolean 值,枚举等。为什么呢? )

最佳答案

从Java 8开始,有关``歧义方法调用''的错误是正确的。
甚至在Java 8之前,您都可以编写

char c = fail();
Object o = fail();
没有编译器错误。当您将诸如condition? 'a': genericMethod()之类的条件传递给诸如String.valueOf(…)之类的方法时,由于其类型推断有限,编译器会为<Object>推断fail()并选择String.valueOf(Object)
但是Java 8引入了Poly Expressions:

The type of a standalone expression can be determined entirely from the contents of the expression; in contrast, the type of a poly expression may be influenced by the expression's target type (§5 (Conversions and Contexts)).


泛型方法的调用和包含多边形表达式的条件(即泛型方法的调用)都是多边形表达式。
因此,尝试调用String.valueOf(char)在该条件下有效,因为我们可以推断<Character>fail()。请注意,这两种方法都不适用于strict invocation context,因为这两种变体都需要装箱或拆箱操作。在loose invocation context中,String.valueOf(Object)String.valueOf(char)均适用,因为在调用Character之后取消对fail()的包装还是对文字char'a'进行包装都无所谓。
由于char不是Object的子类型,并且Object不是char的子类型,因此String.valueOf(Object)String.valueOf(char)都不是more specific,因此会生成编译器错误。

由于没有正式的警告标准,因此判断警告更为困难。在我看来,每一个声称源代码工件已过时的编译器警告都是错误的,尽管该代码在删除代码后将不会做同样的事情(或者删除它甚至会引入错误)。有趣的是,警告在Java 7版本的javac中已经存在,在其中删除强制转换实际上没有任何作用,因此,也许这是一个需要更新的内容。

该问题的解决方法取决于具体情况,并且没有足够的信息。请注意,只有一个分支需要分配给char,以使String.valueOf(char)方法不适用。只要插入评估结果为String的分支,就会发生这种情况。您还可以使用SurroundingClass.<Object>fail()来获得与Java 8之前的编译器推断的类型相同的类型。
或者完全删除通用签名,因为这里不需要。通用方法fail()似乎是一种解决方法,可以在表达式上下文中使用throwing方法。更干净的解决方案将是表达的工厂方法,例如
class Code {
    public static void main(String[] args) throws SpecificExceptionType {
        System.out.println(
            String.valueOf(switch(0) {
                case 0 -> 'a';
                case 1 -> 'b';
                case 2 -> 'c';
                default -> throw fail();
            })
        );
    }
    private static SpecificExceptionType fail() {
        return new SpecificExceptionType();
    }
    static class SpecificExceptionType extends Exception {
    }
}
如果开关表达式不可行,则可以使用
System.out.println(
    String.valueOf(
        true ? 'a' :
        true ? 'b' :
        true ? 'c' :
        Optional.empty().orElseThrow(Code::fail)
    )
);
两者都具有特定于可能引发的异常的实际类型的优点,并且无需求助于未经检查的异常或throws Throwable声明。第二种方法可能会让人觉得很笨拙,但不只是定义一个永不返回任何内容的通用方法。
当然,如果您只接受引入更多的代码,还有其他解决方案,例如专用于字符串转换的辅助方法(没有重载)或非泛型包装方法(用于throwing方法)。或临时变量或类型强制转换或用于通用调用的显式类型等。此外,当使用"" + (expression)(expression).toString()而不是String.valueOf(expression)时,该表达式不是多边形表达式,因此不会产生“歧义方法调用”错误。
当然,由于这是一个错误的警告,因此您还可以保留强制类型转换并将@SuppressWarnings("cast")添加到方法中(并等待直到编译器开发人员将其修复为止)。

关于java - “redundant cast to java.lang.Object”警告需要强制转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64839117/

相关文章:

java - java用正则表达式匹配字符串数组内容

c++ - 一组警告作为错误 g++

c - 为什么 GCC 不在此示例中发出警告

f# - 完整模式匹配的编译时约束

java - 通过后台删除hybris中的动态属性

java - 如果同时修改未 protected Java 集合会发生什么情况?

java - 将 .txt 的内容放入字符串中

C++从1个字符转换为字符串?

MySQL 字符串转换为无符号

C++ double cast void 指针