在Java中布尔类型转换没用吗?
我看到 boolean 的显式强制转换语法在语法上(boolean)
是合法的,但我想不出它的用途。相应的 Boolean 对象——或者更确切地说是在 boolean 和 Boolean 之间来回转换——由自动装箱处理。所以它看起来像是编译器的无用语言工件。是否有我缺少的功能场景?
回答
当重载方法被调用时,它会有所作为。由于要调用的方法由参数的静态类型决定(请参阅JLS,第 15.12.2 节),因此将 a 转换Boolean
为 aboolean
或反之亦然可以更改调用的方法:
class Ideone {
public static void main (String[] args) {
final Boolean b = true;
foo((boolean) b); // prints out "primitive"
foo(b); // prints out "wrapper"
}
public static void foo(boolean b) {
System.out.println("primitive");
}
public static void foo(Boolean b) {
System.out.println("wrapper");
}
}
Ideone Demo
请注意,当从Boolean
to 转换时boolean
,NullPointerException
当 的Boolean
值为时可能会出现a null
。
然而,是否(广泛)使用或应该使用这种行为是另一个争论。
rzwitserloot显示出与另一种情况boolean
,并Object
在他们的答案。虽然 rzwisterloot 的情况看起来很相似,但底层机制是不同的,因为从Object
to的向下转换boolean
是在 JLS 中单独定义的。此外,它容易出现 a ClassCastException
(如果Object
不是 a Boolean
)以及 a NullPointerException
(如果Object
是null
)。
- It’s not uncommon to have overloaded methods accepting `boolean` and `Object` (example: `String.valueOf(…)`). A call with a `Boolean` would also use the method with an `Object` parameter.
- Indeed, this answer would be better with `boolean`/`Object`, which is a lot more realistic
- As a special case, when calling `invokeExact` on a `MethodHandle` you may need this, even when the actual target method is not overloaded. It may be even necessary for the return type.
- @Turing85 it sounds like a valid point to me. 🙂
回答
不是完全。
通常,对基本类型应用强制转换运算符仅用于一个目的,即将一种基本类型转换为另一种。boolean
是唯一具有不能转换为布尔值且布尔值不能转换为其他任何属性的原始类型。
但是,这些还有第二个目的,尽管它在 JLS 中没有明确说明并且是一种可疑的代码风格实践:它有效地触发自动拆箱。它甚至结合了触发自动拆箱和普通类型转换的工作:
Object o = true;
boolean b = (boolean) o;
o = "Hello";
b = (boolean) o;
编译就好了。正如预期的那样,它会在第 4 行导致 ClassCastException。如果没有布尔类型转换,您必须执行以下操作:
boolean b = ((Boolean) o).booleanValue();
这肯定更罗嗦。究竟你到底怎么了常达想投类型的某些表达Object
来boolean
-也许这是一个非常罕见的现象,但它是一个真实的,而且不允许(boolean)
将有更长的取得了JLS,而不是更短(和javac的代码库也不会有任何要么更短)。
- It is in fact explicitly spelled out: https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.5
- `boolean b = (Boolean)o;`
回答
正如其他答案中所述,您可以使用boolean
强制转换来强制自动拆箱或从重载方法中进行选择。作为一种特殊情况,调用invokeExact
onMethodHandle
可能需要这样的转换来选择正确的方法签名,即使对于返回类型也是如此。
但是曾经有一段时间这些功能都不存在,但仍然boolean
允许演员阵容。添加特殊规则 forboolean
不会使语言更简单。但是已经考虑了允许此功能的影响。
当我们查看语言规范的第二版时:
5.1.1 身份转换
任何类型都允许从一个类型转换为同一个类型。这可能看起来微不足道,但它有两个实际后果。首先,始终允许表达式具有所需的类型开始,因此允许简单陈述的规则,即每个表达式都可以进行转换,如果只是简单的身份转换。其次,它意味着为了清楚起见,允许程序包含冗余的强制转换运算符。
唯一允许的涉及类型 boolean 的转换是从
boolean
to的标识转换boolean
。
所以在那个时候,一个boolean
值只能被强制转换为boolean
,这甚至被明确说明,但被有意允许,例如“为了清楚起见”。
考虑一个像foo(bar())
vs.的调用foo((boolean)bar())
。
或者,stringBuffer.append((boolean)someMethod())
。
演员表不能改变程序的行为,但可以向人类读者提供额外的信息。
今天的版本仍然声明允许身份转换,但不限制转换boolean
为身份的转换,因为我们现在可以在boolean
引用类型之间进行转换。
在旧版本中甚至还有第二次提及:
15.16 强制转换表达式
强制转换表达式在运行时将一种数值类型的值转换为另一种数值类型的类似值;或在编译时确认表达式的类型是布尔值;或在运行时检查引用值是否引用其类与指定引用类型兼容的对象。
由于当时无法在原始类型和引用类型之间进行转换,因此对于强制转换、数字转换、引用类型更改或“在编译时确认表达式的类型为布尔型”有三种不同的用例。
因为这是boolean
演员在该 Java 版本中唯一可以做的事情。