你怎么能打印:“true”+ null但不是:true + null?

时间:2014-02-05 15:33:02

标签: java null

以下编译:

System.out.println("true" + null);

我假设是因为字符串的存在,也将“null”转换为字符串。

然而,由于这有效:

System.out.println(true);

似乎以下内容也会编译,因为显然“true”函数是一个字符串。

System.out.println(true + null);

但是,它没有编译。

任何人都可以解释一下吗?

6 个答案:

答案 0 :(得分:2)

+运算符适用于数字(intfloatdouble)和String s,但在这种情况下,您使用的是添加 booleanObjectnull),这是错误的。

  

但是,因为这可行

System.out.println(true);
     

似乎以下内容也会编译,因为显然“true”函数是一个字符串。

     

System.out.println(true + null);

System.out.println(boolean)以来,以前的作品会将boolean转换为String。后者不会。


null为什么转换为"null"而不会产生任何问题进行一些研究,因为:

  • null.toString()由于显而易见的原因无法编译
  • StringBuilder.append(null)无法编译
  • String.valueOf(null)编译但在运行时抛出NullPointerException

看起来编译器直接使用null,它会首先创建一个Object o然后String s变量并为其分配null,然后使用String.valueOf(s) }。所以,这段代码:

System.out.println("true" + null);

实际上是

System.out.println(new StringBuilder().append("true").append((Object)null).toString());

如果我们做反向:

 System.out.println(null + "true");

这将成为:

System.out.println(new StringBuilder().append((Object)null).append("true").toString());

为了表明这既不是魔法也不是黑魔法,我只是写了一个简单的代码来复制这种情况:

public class TestNullString {
    public static void main(String[] args) {
        nullPlusString();
        stringPlusNull();
    }
    public static void nullPlusString() {
        System.out.println(null + "foo");
    }
    public static void stringPlusNull() {
        System.out.println("foo" + null);
    }
}

使用java TestNullString.java编译该类,然后使用生成的javap -c TestNullString.class对其进行反编译(由反编译器本身生成的注释,而不是我的):

Compiled from "TestNullString.java"
public class TestNullString {
  public TestNullString();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #2                  // Method nullPlusString:()V
       3: invokestatic  #3                  // Method stringPlusNull:()V
       6: return        

  public static void nullPlusString();
    Code:
       0: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: new           #5                  // class java/lang/StringBuilder
       6: dup           
       7: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
      10: aconst_null   
      11: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      14: ldc           #8                  // String foo
      16: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      25: return        

  public static void stringPlusNull();
    Code:
       0: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: new           #5                  // class java/lang/StringBuilder
       6: dup           
       7: invokespecial #6                  // Method java/lang/StringBuilder."<init>":()V
      10: ldc           #8                  // String foo
      12: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: aconst_null   
      16: invokevirtual #7                  // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
      19: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      25: return        
}

通过执行StringBuilder#append(Object),它显示:

public StringBuilder append(Object obj) {
    return append(String.valueOf(obj));
}

String#valueOf(Object)实施:

public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

这完全说明了为什么null最终成为"null"

解释这一点的另一项努力是在这里完成的:Concatenating null strings in Java

答案 1 :(得分:1)

它无法编译,因为语句操作数truenull不适用于+操作。适用的夫妇是:

  • 所有数字类型,包括包装器。例如:new Integer(1) + new Integer(2)
  • String + Object(因为为每个对象定义了.toString()方法)。例如:"newObject().toString() + "cde"
  • String + null。例如:"abc" + null

备注(感谢@Luiggi和@Sotirios):

  • 结果String.valueOf(null)将无法作为可能的操作数,因为它会抛出NullPointerException ...
  • ...但String.valueOf((Object) null)将返回String"null"

答案 2 :(得分:1)

since apparently "true" functions as a string.

这个假设是错误的。它有效,因为你打电话

public void println(boolean x)

然而,

true + null

不是Java中的有效语句,因为您不能添加或附加布尔值和对象。

答案 3 :(得分:1)

来自JLS

  

如果+运算符的任一操作数的类型是String,那么   操作是字符串连接。

并且由StringBuilder.append()进行连接。

答案 4 :(得分:0)

parens之间的语句在打印之前执行。问题不在于字符串转换,正如其他人所说,问题是

true + null

是一个没有意义的补充问题。

"true" + null

然而,不是添加 - 它是字符串连接。由于“true”是一个字符串,+的含义从“添加”变为“连接”。

答案 5 :(得分:0)

如果是

System.out.println(true + null);

它尝试将null转换为boolean,因为boolean只有falsetrue值,所以它不能转换,也不能编译。

如果是

System.out.println("true" + null);

null已投放到字符串,因为String可以有null值(字符串是Object