unboxing或toString()用于java中的sysout

时间:2010-01-23 12:11:12

标签: java

我们知道当我们在sysout(System.out.Println)语句中使用对象时,会调用toString方法。和原始它直接打印。但是当我们使用任何Wrapper类的对象时,请使用假设Integer,如下面的

      Integer i = new Integer(10)
      System.out.Println(i);

是toString()负责打印还是取消装箱?

3 个答案:

答案 0 :(得分:10)

快速测试和调试运行显示调用了print(Object),而不是print(int)

检查这个的好方法是:

Integer val = null;
System.out.print(val);

如果使用了un-boxing,则会抛出NullPointerException。但是,这不会发生,它会打印字符串null,这是传入null时String.valueOf(Object)的输出。

要记住的另一个方面是在Java 5之前存在PrintStream。当在Java 5中引入自动装箱时,必须确保使用PrintStream的任何现有代码不会突然出现其行为改变。因此,调用print(Object)的任何现有代码都不得突然将其行为更改为调用print(int),而只是因为新的语言功能。必须始终保持向后兼容性。

答案 1 :(得分:5)

  

(...)但是当我们使用任何Wrapper类类型时   使用对象说假设整数   喜欢以下

  Integer i = new Integer(10)
  System.out.println(i);
     

是toString()负责的   打印还是取消装箱?

您正在将Object传递给println,因此显然println(Object obj)会调用String.valueOf(obj)来写The Java Language Specification的输出,如果{{{}} obj.toString() 1}}不是obj

PS:没有冒犯,但是,你为什么不看看消息来源呢?

更新:我可能错过了问题的重点(如果可能的话,这会误导当前的形式)。实际上,问题可能是:

  

(...)但是当我们使用任何Wrapper类类型时   使用对象说假设整数   喜欢以下

null
     

将采用何种方法:    Integer i = new Integer(10) System.out.println(i); println(Object)

如果这就是问题所在,那么答案就在于15.12 Method Invocation Expressions。为简化起见,在运行时调用的方法将是在编译时确定的方法。现在,编译器如何确定将被调用的方法?嗯,这在15.12.2 Compile-Time Step 2: Determine Method Signature部分有解释。我不会涵盖所有的细节,规范比我做得好,但基本上,第一步是找到要搜索的类或接口,第二步是找到所有适用的方法,然后拿起最具体的方法方法,第三步是验证所选方法是否合适。我将专注于第二步(这里有趣的一步)。详见第(§15.12.2.2)部分:

  

如果是一种方法,则适用   适用于子类型(§15.12.2.3),   适用于方法调用   转换(§15.12.2.4),或者它是   适用的变量方法   (§15.12.2.1)

     

确定的过程   适用性从确定开始   潜在适用的方法   (§15.12.2.2)。其余部分   过程分为三个阶段。

     
     

<强>讨论

     

分裂的目的   阶段是为了确保兼容性   旧版本的Java编程   语言。

     
     

第一阶段(§15.12.2.3)   无需执行重载决策   允许装箱或拆箱   转换,或使用变量   arity方法调用。如果不   在此期间找到适用的方法   阶段然后处理继续到   第二阶段。

     
     

<强>讨论

     

这可以保证任何调用   在旧版本中有效   语言不被认为是模棱两可的   由于引入   变量arity方法,隐含   装箱和/或拆箱。

     
     

第二阶段(§15.12.2.4)   执行重载分辨率   允许装箱和拆箱,但是   仍然排除使用变量   arity方法调用。如果不   在此期间找到适用的方法   阶段然后处理继续到   第三阶段。

     
     

<强>讨论

     

这确保了变量arity   如果一个方法永远不会被调用   存在适用的固定方法。

     
     

第三阶段(§8.4.4)   允许重载与   变量arity方法,拳击和   开箱。

     

确定方法是否   在适用的情况下适用   通用方法(§15.12.2.7),   要求实际的类型参数   决心。实际类型参数可以   明确地或隐含地传递。如果   他们必须隐含地通过   从中推断§15.12.2.5   参数表达式的类型。

     

如果有多种适用方法   其中一个被确认   适用性测试的三个阶段,   然后选择最具体的一个,   如(§5.3)部分所述。   请参阅以下小节   的信息。

在这种特殊情况下,println(int)适用于子类型(并且println(Obj)适用于调用转换,因为装箱/取消装箱是转化phase 1)。所以编译器将进入(§15.12.2.3)。如果我们看一下最后一句话:

  

如果找不到子类型适用的方法,则搜索适用的方法将继续第2阶段(§15.12.2.5)。否则,在通过子类型适用的方法中选择最具体的方法{{3}}。

这里,没有任何其他适用于子类型的方法,所以这就是结束,println(int)将被调用(因此println(Object)将被调用,以回答初始问题)。

答案 2 :(得分:4)

所有这些都早于1.5中引入的autoboxing回答这些问题的代码 - 或API文档 - 在1.5+时根本没有变化。

基本上,在行的末尾是非基元的toString方法,例如Integer的实例。

首先,对于原始人来说,每个人都有不同的待遇。例如,对于int

  

打印整数。产生的字符串   by String.valueOf(int)已翻译   根据平台的字节数   默认字符编码,以及这些   字节完全写入   write(int)方法的方式。

但对于像Integer这样的对象,println调用print,其中:

  

打印对象。产生的字符串   通过String.valueOf(Object)方法   被翻译成字节   平台的默认字符   编码,并写入这些字节   完全按照的方式   write(int)方法。

那么valueOf使用什么?这是您的问题的答案:对于Integer,调用其toString方法。这来自String.valueOf

上的文档
  

如果参数为null,则为字符串   等于“null”;否则,价值   返回obj.toString()。