"redundant cast to java.lang.Object" 必要演员表警告
"redundant cast to java.lang.Object" warning for necessary cast
考虑这个 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
是一个有用的布尔表达式的替代。我们可以忽略第一个 ? :
以外的部分(在实际代码中,有很多)。)
这个'obviously'给出了错误。
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
是不同的 类。“开关”是不可枚举的类型。fail
是类断言方法的伴侣,所以这就是它抛出的原因内部(未经检查的非空)异常。
我实际修复它的方式是,与此无关,我重新安排了代码,因此其中也有一些文字字符串。否则,我会使用无意义的 Object.class.cast
等同于 (Object)
。我真正想知道的是:wtf?
*实际上 real real 代码通过不同语言的词法分析器,不区分文字字符、字符串、各种数字、布尔值、枚举等。为什么会吗?)
如果我忽略我对 String
的前瞻性要求,我可以写:
String.valueOf((Character)(
true ? 'a' :
fail()
))
要同时处理 char
和 String
我可以使用 weird:
String.valueOf((Comparable<?>)(
true ? 'a' :
fail()
))
或者使用Java序列化一些有用的东西:
String.valueOf((java.io.Serializable)(
true ? 'a' :
fail()
))
估计是个bug,但是懒得打了bugs.java.com。
另一种解决方法是引入一个不必要的本地:
Object symbol =
true ? 'a' :
fail();
System.out.println(String.valueOf(symbol));
这不是必需的,但可以将类型参数设置为 fail()
显式并避免任何讨厌的显式转换:
String.valueOf(
true ? 'a' :
Code.<Object>fail()
)
可爱的语法!或者,fail()
可以有一个多余的转换...
问题是三元运算符的两个分支return类型不同
这个怎么样:
System.out.println(
String.valueOf(
true ? (Object)'a' : fail()
)
);
明确地装箱角色是一种可能性:
class Code {
public static void main(String[] args) throws Throwable {
System.out.println(
String.valueOf(
true ? Character.valueOf('a') : fail()
)
);
}
private static <R> R fail() {
throw null;
}
}
关于“模棱两可的方法调用”的错误是正确的,因为 Java 8.
甚至在 Java 8 之前,您就可以写
char c = fail();
Object o = fail();
没有编译器错误。当您将 condition? 'a': genericMethod()
之类的条件传递给 String.valueOf(…)
之类的方法时,编译器会为 fail()
推断 <Object>
并选择 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, as both variants require a boxing or unboxing operation. In a loose invocation context,String.valueOf(Object)
和 String.valueOf(char)
都适用,因为我们在调用 [=16] 后是否拆箱 Character
并不重要=] 或将文字 'a'
.
的 char
框起来
因为 char
不是 Object
的子类型并且 Object
不是 char
的子类型,所以方法,String.valueOf(Object)
和 String.valueOf(char)
,是more specific,因此会产生编译错误。
判断警告比较困难,因为没有正式的警告标准。在我看来,每个声称源代码工件已过时的编译器警告都是不正确的,尽管代码在删除后不会执行相同的操作(或者删除它甚至会引入错误)。有趣的是,警告确实已经存在于 Java 7 的 javac
版本中,其中删除强制转换确实没有任何区别,所以也许,它是一个需要更新的遗留问题。
问题的解决方法取决于上下文,并且没有足够的信息。请注意,只需要一个分支不可分配给 char
,以使方法 String.valueOf(char)
不适用。只要您插入计算结果为 String
的分支,就会发生这种情况。您还可以使用 SurroundingClass.<Object>fail()
获得 pre-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 {
}
}
如果switch表达式不可行,你可以使用
System.out.println(
String.valueOf(
true ? 'a' :
true ? 'b' :
true ? 'c' :
Optional.empty().orElseThrow(Code::fail)
)
);
两者都具有明确潜在抛出异常的实际类型的优势,并且不需要求助于未经检查的异常或 throws Throwable
声明。第二个可能感觉很老套,但只不过是定义了一个从不 returns 任何东西的通用方法。
当然,还有其他的可能性来解决它,如果你只是接受引入更多的代码,比如一个没有重载的字符串转换的专用帮助方法,或者一个非通用的包装方法,用于 throwing 方法。或临时变量或类型转换或泛型调用的显式类型等。此外,当使用 "" + (expression)
或 (expression).toString()
而不是 String.valueOf(expression)
时,表达式不是多边形表达式,因此,不产生“模棱两可的方法调用”错误。
当然,由于这是错误警告,您也可以保留转换并向方法添加 @SuppressWarnings("cast")
(并等待编译器开发人员修复此问题)。
简单问题的简单回答:
class Code {
public static void main(String[] args) throws Throwable {
System.out.println((
true ? 'a' :
true ? 'b' :
true ? 'c' :
fail()).toString()
);
}
private static <R> R fail() {
throw null;
}
}
只要您没有任何 null
值,此代码就有效。要同时涵盖 null
个值,您需要引入一个额外的方法:
class Code {
public static void main(String[] args) throws Throwable {
System.out.println(valueOf(
true ? 'a' :
true ? 'b' :
true ? 'c' :
fail()
)
);
}
private static <R> R fail() {
throw null;
}
static String valueOf(Object object) {
return String.valueOf(object);
}
}
两种解决方案都不需要编辑 ? :
的许多行
编译器警告和错误都不是错误。在错误情况下,您为编译器提供的信息太少,无法选择正确的方法,在第二次尝试中,您告诉编译器将 Object 转换为 Object ,这是不必要的,值得至少产生一个警告 ;-)
将表达式的结果提取到局部变量:
T obj =
true ? 'a' :
true ? 'b' :
true ? 'c' : fail();
System.out.println(String.valueOf(obj));
您可以将电话与供应商包装起来,以获得一种方式:
class Code {
public static void main(String[] args) throws Throwable {
System.out.println(((Supplier<Object>) () ->
true ? 'a' :
false ? 'b' :
false ? 'c' :
fail()).get());
}
private static <R> R fail() { throw null; }
}
'a'
不是 String
符号;将其替换为 "a"
(而且我也不完全理解用例 - 或者可能会使用正则表达式引擎编写完全不同的代码)。但是,为了避免毫无意义的投射......只需检查 instanceof
,你甚至想投射什么。与此类似,几乎没有 space 模棱两可的调用和无用的来回转换。
考虑这个 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
是一个有用的布尔表达式的替代。我们可以忽略第一个 ? :
以外的部分(在实际代码中,有很多)。)
这个'obviously'给出了错误。
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
是不同的 类。“开关”是不可枚举的类型。fail
是类断言方法的伴侣,所以这就是它抛出的原因内部(未经检查的非空)异常。
我实际修复它的方式是,与此无关,我重新安排了代码,因此其中也有一些文字字符串。否则,我会使用无意义的 Object.class.cast
等同于 (Object)
。我真正想知道的是:wtf?
*实际上 real real 代码通过不同语言的词法分析器,不区分文字字符、字符串、各种数字、布尔值、枚举等。为什么会吗?)
如果我忽略我对 String
的前瞻性要求,我可以写:
String.valueOf((Character)(
true ? 'a' :
fail()
))
要同时处理 char
和 String
我可以使用 weird:
String.valueOf((Comparable<?>)(
true ? 'a' :
fail()
))
或者使用Java序列化一些有用的东西:
String.valueOf((java.io.Serializable)(
true ? 'a' :
fail()
))
估计是个bug,但是懒得打了bugs.java.com。
另一种解决方法是引入一个不必要的本地:
Object symbol =
true ? 'a' :
fail();
System.out.println(String.valueOf(symbol));
这不是必需的,但可以将类型参数设置为 fail()
显式并避免任何讨厌的显式转换:
String.valueOf(
true ? 'a' :
Code.<Object>fail()
)
可爱的语法!或者,fail()
可以有一个多余的转换...
问题是三元运算符的两个分支return类型不同
这个怎么样:
System.out.println(
String.valueOf(
true ? (Object)'a' : fail()
)
);
明确地装箱角色是一种可能性:
class Code {
public static void main(String[] args) throws Throwable {
System.out.println(
String.valueOf(
true ? Character.valueOf('a') : fail()
)
);
}
private static <R> R fail() {
throw null;
}
}
关于“模棱两可的方法调用”的错误是正确的,因为 Java 8.
甚至在 Java 8 之前,您就可以写
char c = fail();
Object o = fail();
没有编译器错误。当您将 condition? 'a': genericMethod()
之类的条件传递给 String.valueOf(…)
之类的方法时,编译器会为 fail()
推断 <Object>
并选择 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, as both variants require a boxing or unboxing operation. In a loose invocation context,String.valueOf(Object)
和 String.valueOf(char)
都适用,因为我们在调用 [=16] 后是否拆箱 Character
并不重要=] 或将文字 'a'
.
char
框起来
因为 char
不是 Object
的子类型并且 Object
不是 char
的子类型,所以方法,String.valueOf(Object)
和 String.valueOf(char)
,是more specific,因此会产生编译错误。
判断警告比较困难,因为没有正式的警告标准。在我看来,每个声称源代码工件已过时的编译器警告都是不正确的,尽管代码在删除后不会执行相同的操作(或者删除它甚至会引入错误)。有趣的是,警告确实已经存在于 Java 7 的 javac
版本中,其中删除强制转换确实没有任何区别,所以也许,它是一个需要更新的遗留问题。
问题的解决方法取决于上下文,并且没有足够的信息。请注意,只需要一个分支不可分配给 char
,以使方法 String.valueOf(char)
不适用。只要您插入计算结果为 String
的分支,就会发生这种情况。您还可以使用 SurroundingClass.<Object>fail()
获得 pre-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 {
}
}
如果switch表达式不可行,你可以使用
System.out.println(
String.valueOf(
true ? 'a' :
true ? 'b' :
true ? 'c' :
Optional.empty().orElseThrow(Code::fail)
)
);
两者都具有明确潜在抛出异常的实际类型的优势,并且不需要求助于未经检查的异常或 throws Throwable
声明。第二个可能感觉很老套,但只不过是定义了一个从不 returns 任何东西的通用方法。
当然,还有其他的可能性来解决它,如果你只是接受引入更多的代码,比如一个没有重载的字符串转换的专用帮助方法,或者一个非通用的包装方法,用于 throwing 方法。或临时变量或类型转换或泛型调用的显式类型等。此外,当使用 "" + (expression)
或 (expression).toString()
而不是 String.valueOf(expression)
时,表达式不是多边形表达式,因此,不产生“模棱两可的方法调用”错误。
当然,由于这是错误警告,您也可以保留转换并向方法添加 @SuppressWarnings("cast")
(并等待编译器开发人员修复此问题)。
简单问题的简单回答:
class Code {
public static void main(String[] args) throws Throwable {
System.out.println((
true ? 'a' :
true ? 'b' :
true ? 'c' :
fail()).toString()
);
}
private static <R> R fail() {
throw null;
}
}
只要您没有任何 null
值,此代码就有效。要同时涵盖 null
个值,您需要引入一个额外的方法:
class Code {
public static void main(String[] args) throws Throwable {
System.out.println(valueOf(
true ? 'a' :
true ? 'b' :
true ? 'c' :
fail()
)
);
}
private static <R> R fail() {
throw null;
}
static String valueOf(Object object) {
return String.valueOf(object);
}
}
两种解决方案都不需要编辑 ? :
编译器警告和错误都不是错误。在错误情况下,您为编译器提供的信息太少,无法选择正确的方法,在第二次尝试中,您告诉编译器将 Object 转换为 Object ,这是不必要的,值得至少产生一个警告 ;-)
将表达式的结果提取到局部变量:
T obj =
true ? 'a' :
true ? 'b' :
true ? 'c' : fail();
System.out.println(String.valueOf(obj));
您可以将电话与供应商包装起来,以获得一种方式:
class Code {
public static void main(String[] args) throws Throwable {
System.out.println(((Supplier<Object>) () ->
true ? 'a' :
false ? 'b' :
false ? 'c' :
fail()).get());
}
private static <R> R fail() { throw null; }
}
'a'
不是 String
符号;将其替换为 "a"
(而且我也不完全理解用例 - 或者可能会使用正则表达式引擎编写完全不同的代码)。但是,为了避免毫无意义的投射......只需检查 instanceof
,你甚至想投射什么。与此类似,几乎没有 space 模棱两可的调用和无用的来回转换。