【问题标题】:(String) or .toString()?(字符串)还是 .toString()?
【发布时间】:2010-10-15 03:37:39
【问题描述】:

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

在这种方法中,我完全知道“o”中有一个String,它不为空。无需检查或执行其他操作。我必须像对待String 对象一样对待它。

只是好奇-什么更便宜-将其转换为String,还是使用Object.toString()? 还是按时间-/cpu-/mem-价格都一样?

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

而且根本不可能是null。我只是想说我不需要检查它是否为空或为空。就我而言,总是有一个非空字符串。

【问题讨论】:

  • 在 .NET 世界中,我们对其进行了测量,并且 ToString() 更快。考虑到为什么会这样,几乎可以肯定的是,jitting JVM 也是如此。

标签: java casting


【解决方案1】:

转换为字符串更便宜,因为这不需要外部函数调用,只需要内部类型检查。

【讨论】:

  • 您是否在多个 JRE 上测试过它?对于.NET 中的这种情况,我已经看到了令人惊讶的结果。实际上,我怀疑性能在现实生活中是否重要 - 但从防御性编码的角度来看,投射更好。
  • 方法调用应该被内联。最好使用泛型来移除(显式)演员表。
  • @Jon Skeet :我同意性能差异不会太大。 @Tom Hawtin:由于在编译时不知道将要接收的对象的类型,因此我看不到方法调用如何内联。你能澄清一下吗?
  • @euphoria83:由 JIT 编译器内联,而不是由 javac。
  • 其实不行,方法不能内联。类型只知道是对象,实际实现取决于运行时类型。哪个更快仍然取决于实现,但据我记得(我实际上曾在某个时候用微基准测试过),铸造似乎更快。这不是一个明显的答案:类型检查并不总是更快。对于 String 类型,它可以是因为它是一个对象(不是接口),并且是最后一个。
【解决方案2】:

我会使用演员表。这验证了你的“知识”它是一个字符串。如果由于某种原因您最终遇到了错误并且有人传入了字符串以外的内容,我认为抛出异常(强制转换会这样做)比继续使用有缺陷的数据执行要好。

【讨论】:

    【解决方案3】:

    根据Silly performance musings: x.toString() vs (String)x

    最后,结果出人意料 clear: 至少快两倍 将对象转换为字符串而不是调用 Object.toString()

    【讨论】:

    • 我现在运行该代码,差异可以忽略不计(Mac,Java 8)
    【解决方案4】:

    如果您知道 Object o 是一个字符串,我会说只需将其转换为字符串并以这种方式强制执行。在您确定是 String 的对象上调用 toString() 可能只会增加混乱。

    如果 Object o 可能不是字符串,则需要调用 toString()。

    【讨论】:

    • 这对我来说是正确的答案。为什么?因为转换 (string)Registry.GetValue... 会在尝试转换 Int32 对象时抛出异常,而 Registry.GetValue...ToString() 会按预期工作。
    【解决方案5】:

    我不会太在意性能,如果这个操作每秒只执行几千次 - 没有明显的区别。

    但是,我会担心“知道”输入。你有一个接受Object 的方法,你应该这样对待它,即你不应该知道关于参数的任何事情,除了它遵循Object 接口,这恰好发生在有一个toString() 方法。在这种情况下,我强烈建议使用该方法,而不是仅仅假设任何事情。

    OTOH,如果输入总是Stringnull,只需将方法更改为接受Strings,并明确检查nulls(你应该这样做无论如何,无论何时与非原始人打交道......)

    【讨论】:

    • 我说我的问题没有有价值的意义 :) 我只是好奇什么是理论上更便宜。但是还是谢谢
    • 成本将取决于虚拟机在虚拟方法调用与类型检查方面的效率。这是特定于实现的。
    【解决方案6】:

    鉴于引用类型是一个对象,并且所有对象都有一个 toString(),只需调用 object.toString()。 String.toString() 只是返回这个。

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

    【讨论】:

      【解决方案7】:

      如果你在 "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();
      }
      

      【讨论】:

      • 前 2 个 sn-ps 不会真正编译(final 变量可能尚未初始化)。你需要一个else,它要么抛出异常,要么将str初始化为某个东西。
      【解决方案8】:

      我奇怪地发现强制转换比 tostring 调用所隐含的 vtable 查找要慢。

      【讨论】:

        【解决方案9】:

        不能有“o 中的空字符串”。如果 o 为 null,则它不包含 null 字符串,它只是 null。只需先检查 o 是否为空。如果你 cast 或在 null 上调用 ToString() 你会崩溃。

        【讨论】:

        • 铸造 null 不会崩溃。它甚至不会抛出 NullPointerException,它只会将 null 调用到新类型。 :)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-13
        • 1970-01-01
        • 2021-03-28
        • 1970-01-01
        • 2015-01-01
        • 2013-02-23
        相关资源
        最近更新 更多