考虑这个最小的、可复制的例子:
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
是一个有用的布尔表达式的替代。我们可以忽略超过第一个 ? :
(在真正的代码中,有很多)
这个“显然”给出了错误。
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
这是编译器中的一个bug警告或错误吗?如何修复它,使代码合理并且没有警告或错误?
(编辑:我已经稍微改变了mre。 throws Throwable
来自模板。真正的代码使用文字字符*和 String.valueOf
在其他地方它使用 String.valueOf(char)
超载,所以 toString()
是有问题的(哦,java!)。该代码避免全局状态,例如 System.out
,和 symbol
以及 fail
他们在不同的班级。“开关”属于不可枚举类型。 fail
是类Assert方法的伴侣,所以这就是为什么它在内部抛出一个(未检查的非null)异常。
我实际上是如何修复它的,我重新排列了代码,所以里面也有一些文字字符串。否则,我会用毫无意义的 Object.class.cast
相当于 (Object)
. 我真正想知道的是:wtf?
- 实际上,真正的代码是通过一个不同语言的lexer来实现的,它不区分文字字符、字符串、各种数字、布尔值、枚举等。为什么呢?)
8条答案
按热度按时间qco9c6ql1#
'a'
不是一个String
符号;换成"a"
(我也不完全理解这个用例——或者可能会使用regex引擎编写完全不同的用例)。但是,为了避免无意义的铸造…只需检查instanceof
,你想投的东西。与此类似,没有多少空间来进行模棱两可的调用和无用的来回转换。sh7euo9m2#
问题是三元运算符的两个分支返回不同的类型。
这个怎么样:
qyuhtwio3#
简单问题的简单答案:
只要您没有任何
null
价值观。也包括null
需要引入其他方法的值:两种解决方案都不需要编辑
? :
编译器警告和错误都不是bug。在错误情况下,您为编译器提供的信息太少,无法选择正确的方法,在第二次尝试中,您告诉编译器将一个对象强制转换为一个不必要且至少值得产生警告的对象;-)gz5pxeao4#
对角色进行显式装箱是一种可能性:
e0uiprwp5#
您可以与供应商联系以获得以下方法:
avkwfej46#
如果我忽略了我对
String
我可以写:两者兼备
char
以及String
我可以用这个奇怪的词:或者使用java序列化实现一些有用的功能:
它应该被认为是一个bug,但是我不想和bug.java.com打交道。
另一种解决方法是引入不必要的本地解决方案:
这应该不是必需的,但是可以使类型参数
fail()
显式并避免任何讨厌的显式强制转换:可爱的语法!或者,
fail()
可能有多余的演员。。。31moq8wy7#
将表达式的结果提取到局部变量:
vecaoik18#
关于“不明确的方法调用”的错误是正确的,因为java 8.
甚至在java之前 8,你会写字
没有编译器错误。当你通过一个有条件的
condition? 'a': genericMethod()
像这样的方法String.valueOf(…)
,编译器推断<Object>
为了fail()
并挑选String.valueOf(Object)
由于其有限的类型推断。但是java 8个表达式:
独立表达式的类型可以完全由表达式的内容决定;相反,多边形表达式的类型可能受表达式的目标类型的影响(§5(转换和上下文)。
泛型方法的调用和包含poly表达式的条件表达式(即泛型方法的调用)都是poly表达式。
所以我想
String.valueOf(char)
是有条件的,我们可以推断<Character>
为了fail()
. 请注意,这两种方法都不适用于严格的调用上下文,因为这两种变体都需要装箱或拆箱操作。在松散的调用上下文中,String.valueOf(Object)
以及String.valueOf(char)
是适用的,因为我们是否拆开Character
调用后fail()
或者盒子char
文字的'a'
.自
char
不是的子类型Object
以及Object
不是的子类型char
,两种方法都不是,String.valueOf(Object)
也不是String.valueOf(char)
,更具体,因此会生成编译器错误。对警告的判断比较困难,因为警告没有正式的标准。在我看来,每一个声称源代码工件已经过时的编译器警告都是不正确的,尽管在删除源代码工件后,代码不会做同样的事情(或者删除它甚至会引入错误)。有趣的是,这个警告在java中已经存在了 7的版本
javac
,删除演员阵容确实没有什么区别,所以也许,这是一个需要更新的遗留问题。这个问题的解决方法取决于上下文,并且没有足够的信息。请注意,只需要一个不可分配的分支
char
,使方法String.valueOf(char)
不适用。一旦插入计算结果为的分支,就会发生这种情况String
. 你也可以用SurroundingClass.<Object>fail()
以获得与前java相同的类型 8个编译器。或者完全删除泛型签名,因为这里不需要它。泛型方法
fail()
在表达式上下文中似乎有一个抛出方法。更干净的解决方案将是表达式的工厂方法,例如。如果switch表达式不可行,可以使用
两者的优点都是对可能抛出的异常的实际类型非常具体,并且不需要求助于未检查的异常或异常
throws Throwable
声明。第二种方法可能会让人觉得很粗糙,但只不过是定义了一个从不返回任何内容的泛型方法。当然,如果您接受更多代码的引入,也有其他的解决方法,比如用于字符串转换的专用helper方法(无重载)或用于抛出方法的非泛型 Package 方法。或者临时变量或类型为泛型调用强制转换或显式类型等
"" + (expression)
或者(expression).toString()
而不是String.valueOf(expression)
,表达式不是poly表达式,因此,不是pro杜“方法调用不明确”错误。当然,由于这是一个错误的警告,你也可以保留演员阵容并添加一个
@SuppressWarnings("cast")
方法(并等待编译器开发人员修复)。