(String) 还是 .toString()?

98

我有一个带有Object o参数的方法。

在这个方法中,我确切地知道“o”中有一个非空的String。不需要检查或做其他事情。我必须像处理String对象一样对待它。

只是好奇 - 将其强制转换为String,还是使用Object.toString()更便宜? 或者在时间/ CPU / 内存价格方面是否相同?

更新: 该方法接受Object,因为它是接口的实现。无法更改参数类型。

而且它根本不能为null。我只是想说我不需要检查它是否为null或为空。在我的情况下,始终存在一个非空字符串。


1
在.NET世界中,我们测量过了,ToString()更快。鉴于这种情况,同样几乎可以肯定地认为,在JIT编译的JVM中也是如此。 - Joshua
9个回答

81

将其强制转换为字符串更加节省成本,因为这不需要外部函数调用,只需要内部类型检查。


4
你是否在多个JRE上进行了测试?我曾在.NET中看到过类似情况的惊人结果。实际上,我怀疑这种性能问题在现实生活中并不会有太大影响,但从编写防御性代码的角度来看,进行强制类型转换更为可靠。 - Jon Skeet
方法调用应该被内联。使用泛型来消除(显式)转换将是最佳选择。 - Tom Hawtin - tackline
@Jon Skeet:我同意性能差异不会太大。@Tom Hawtin:由于在编译时无法知道将要接收的对象类型,我无法看出方法调用如何被内联。您能否请澄清一下? - euphoria83
@euphoria83:这是由JIT编译器内联而不是javac进行内联。 - Michael Myers
实际上,方法无法进行内联。类型仅为Object,实际实现取决于运行时类型。哪个更快仍取决于实现,但据我所记(我曾经用微基准测试进行过测试),强制转换似乎更快。这并不是一个明显的答案:类型检查并不总是更快。对于String类型,它可能会更快,因为它是一个对象(而不是接口),而且是最终的。 - StaxMan
想在代码审查中反对使用“将类型转换为字符串”,然后看到了这个SO问题。好知道 :) - Wahib Ul Haq

51

我会使用类型转换(cast)。这样可以验证你的“知识”确实是字符串。如果由于某些原因你遇到了错误,并且有人传入的不是字符串,我认为最好抛出异常(类型转换会做到这一点),而不是继续使用有缺陷的数据。


39

2
我现在运行了那段代码,差别微不足道(Mac,Java 8)。 - Stefan L

9
如果您知道对象o是一个字符串,我建议将其转换为字符串并强制执行。调用toString()方法可能会增加混淆,因为您已经确定该对象是一个字符串。
如果对象o可能是除字符串以外的任何类型,您需要调用toString()方法。

1
这对我来说是正确的答案。为什么?因为将(string)Registry.GetValue...强制转换为Int32对象时会抛出异常,而Registry.GetValue...ToString()则按预期工作。 - gravity

3

如果这个操作每秒只执行几千次,性能不是太值得担心。但是,我会担心你是否“知道”输入参数的情况。你有一个接受Object的方法,你应该把它当作Object处理,也就是说,你不应该“知道”任何关于参数的信息,只需要遵循Object接口,也就是具有toString()方法即可。在这种情况下,我强烈建议使用该方法,而不是假定其他内容。

另一方面,如果输入始终为String或null,请将方法更改为接受字符串,并显式检查null(无论何时处理非基元类型都应该这样做...)


我说我的问题没有有价值的意义 :) 我只是好奇从理论上讲哪个更便宜。不管怎样还是谢谢。 - Vugluskr
成本将取决于虚拟方法调用和类型检查的 VM 效率。这是实现特定的。 - Jon Skeet

2

考虑到引用类型是一个对象,而所有的对象都有toString()方法,只需调用object.toString()即可。String.toString()只返回this。

  • toString()输入的代码更少。
  • toString()生成的字节码更少。
  • 强制转换是一种昂贵的操作,而多态调用则不然。
  • 强制转换可能会失败。
  • 使用String.valueOf( object ),如果它不为null,则只调用object.toString()。

1
如果“o”是一个字符串,那么没有太大的区别(可能转换速度更快,但这是VM / Library实现的事情)。
如果“o”可能不是一个字符串,但它应该是一个字符串,那么转换就是你想要的(但你应该让方法接受一个字符串而不是一个对象)。
如果“o”可以是任何类型,那么你必须使用toString - 但一定要先检查是否为null。
void foo(final Object o)
{
    final String str;

    // without this you would get a class cast exception
    // be wary of using instanceof though - it is usually the wrong thing to do
    if(o instanceof String)
    {
        str = (String)o;
    }    
}

或者

void foo(final Object o)
{
    final String str;

    // if you are 100% sure that o is not null then you can get rid of the else
    if(o != null)
    {
        str = o.toString();
    }
}

我宁愿将最后一个编码为:

void foo(final Object o)
{
    final String str;

    if(o == null)
    {
        throw new IllegalArgumentException("o cannot be null");
    }

    str = o.toString();
}

前两个代码片段不会真正编译(final变量可能尚未初始化)。您需要一个“else”语句,它将抛出异常或将“str”初始化为某些内容。 - Bruno Reis

1

o 中不能有“null 字符串”。如果 o 为 null,则它不包含 null 字符串,而是 null。首先检查 o 是否为 null。如果你对 null 进行强制转换或调用 ToString(),程序将会崩溃。


2
强制转换 null 不会崩溃。它甚至不会抛出 NullPointerException,它只是将 null 调用到新类型中。 :) - Bombe

1
我发现奇怪的是,强制类型转换比 tostring 调用所暗示的 vtable 查找要慢。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接