【问题标题】:Java implicit call of toString() when using the "this" keyword使用“this”关键字时 Java 隐式调用 toString()
【发布时间】:2014-02-02 00:28:43
【问题描述】:

我有两个类,ThisTest 和 SimpleTime。 buildString() 方法返回一个带有“this”关键字的连接字符串。当我运行它时,“this”似乎是指 toString() 方法而不是 SimpleTime 类。为什么我使用“this”关键字时会执行 toString() 方法?谢谢。

import java.text.DecimalFormat;

import javax.swing.*;

public class ThisTest {

    public static void main(String args[]) {
        SimpleTime time = new SimpleTime( 12, 30, 19 );

        JOptionPane.showMessageDialog( null, time.buildString(), 
       "Demonstrating the \"this\" Reference", JOptionPane.INFORMATION_MESSAGE);

        System.exit(0);
    }
}

class SimpleTime {
    private int hour, minute, second;

    public SimpleTime( int hour, int minute, int second )
    {
        this.hour = hour;
        this.minute = minute;
        this.second = second;
    }

    public String buildString()
    {
        return "this.toString(): " + this.toString() + 
        "\ntoString(): " + toString() + 
        "\nthis (with implicit toString() call): " + this;
    }
    public String toString()
    {
        DecimalFormat twoDigits = new DecimalFormat("00");

        //"this" not required, because toString does not have
        //local variables with same names as instance variables
        return twoDigits.format( this.hour ) + ":" +
        twoDigits.format( this.minute ) + ":" +
        twoDigits.format( this.second );
    }

    public String anotherString()
    {
        return "Another String for you";
    }

}

【问题讨论】:

  • 你知道this是什么吗?你知道String 连接吗?
  • 您期望发生什么?
  • 我了解字符串连接的作用以及“this”是什么,但我不明白为什么在使用“this”时会调用 toString。
  • 我真的不知道会发生什么

标签: java methods this tostring implicit


【解决方案1】:

因为当您使用字符串连接运算符 (+) 时会发生这种情况。

它调用正在添加的对象的toString() 方法(因为它在Object 中定义,所以肯定存在)。

在您的情况下,这是当前对象 (this),因此您会调用 this.toString()。而且因为您已经在课堂上覆盖了toString(),所以您会得到结果。

编辑添加:注意+ this+ this.toString()之间没有区别;你最终会得到相同的结果。

具体来说,这由section 15.18.1 of the JLS覆盖

如果只有一个操作数表达式是字符串类型,则在运行时对另一个操作数执行字符串转换(第 5.1.11 节)以生成字符串。

§5.1.11 表示:

...

现在只需要考虑参考值:

如果引用为空,则转换为字符串“null”(四个 ASCII 字符 n、u、l、l)。

否则,转换就像通过调用 不带参数的被引用对象的 toString 方法;但如果 调用 toString 方法的结果为 null,则字符串“null” 改为使用。

【讨论】:

  • 谢谢,有道理。如果我在类中没有 toString() 方法会发生什么?
  • @inventorbc 如果你不覆盖toString(),你会从Object获得默认实现,它输出哈希码和类名的组合。
  • 哦,原来如此……当我取出 toString() 方法时,我不断得到 SimpleTime@22c73b。谢谢大佬!
【解决方案2】:

表达式

String s = "literal" + object;

编译成

String s = new StringBuilder().append( "literal" ).append( object ).toString();

如果我们查看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();
}

所以最终会调用对象的toString() 方法。

公然抄袭大卫华莱士的评论:

第 15.18.1 节规定

... 如果只有一个操作数表达式是字符串类型,则在运行时对另一个操作数执行字符串转换(第 5.1.11 节)以生成字符串。 ...

和第 5.1.11 节状态

... 转换是通过调用被引用对象的toString() 方法执行的,不带参数;但如果调用toString() 方法的结果为null,则使用字符串“null”。 ...

看来当前的 JDK 并没有直接遵守 JLS,但最终还是做到了。

【讨论】:

  • 你最后一句话是假的。发生这种情况绝对是 JLS 的一部分。第 15.18.1 节指出“......如果只有一个操作数表达式是字符串类型,则在另一个操作数上执行字符串转换(第 5.1.11 节)以在运行时生成一个字符串......”和第 5.1 节。 11 个状态 - "... 转换是通过调用不带参数的引用对象的 toString 方法执行的;但如果调用 toString 方法的结果为 null,则使用字符串 "null"。 ...”
  • 嗯。我希望在我去为自己找到这两个摘录之前,我会费心阅读布赖恩·罗奇的回答。 :-(
  • @DavidWallace 有趣。不遵循 JLS 的错误 Oracle。我会在答案中注明。
【解决方案3】:

这与this无关。
当与字符串一起使用时,Java 的 + 运算符将在任何非字符串操作数上隐式调用 toString()

这就是像"A" + 1 这样的表达式的编译方式。

【讨论】:

  • 不正确。而且原语没有toString() 方法。
  • @Bohemian:它们首先被自动装箱。
  • 不,它们没有自动装箱。调用 StringBuilder 的 append(int),然后调用 AbstractStringBuilderappend(int) 方法,然后调用 Integer.getChars(),这使得 String 构建变得困难。任何地方都没有自动装箱。
  • @Bohemian 不符合5.1.11 of the the spec
  • 虽然在两个 literals 的情况下,编译器实际上只是处理它,结果存储在 .class 文件的 constant_pool 中(至少在 java 7 中)
【解决方案4】:

在这一行:

 "\nthis (with implicit toString() call): " + this;

操作符'+'处理两个字符串,java隐式调用toString()方法来获取this引用的对象的字符串表示。写“this”或“this.toString()”是完全等价的。

【讨论】:

    猜你喜欢
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-09
    • 1970-01-01
    相关资源
    最近更新 更多