考虑这个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.out
,symbol
和fail
在不同的类中。“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/