【问题标题】:Java type casting. Logic behind (String), .toString() and "" + intJava 类型转换。 (String)、.toString() 和 "" + int 背后的逻辑
【发布时间】:2016-09-16 16:01:10
【问题描述】:

Java 是一种强类型语言。因此,编译代码中的错误更少,可读性更好,但代价是编码速度较慢。因此,需要显式类型转换,这部分很清楚。

这些sn-ps有什么区别:

(String)myInt // obviously doesn't compile
Integer.toString(myInt)
"" + myInt

是纯粹出于历史原因,还是背后有某种意义?
哪种方法合适?

【问题讨论】:

  • 实际上,在 Java 的类型系统健全/足够的情况下,类型 casting 是您不应该做的一件事。
  • 在这种情况下,什么是(字符串)?

标签: java string casting tostring


【解决方案1】:

如前所述,(String) myInt 是一种类型转换。在 Java 中,我们可以在原语中进行强制转换,也可以在对象层次结构中向上进行强制转换。由于int 是一个原始的,String 是一个对象,所以我们遇到了问题。即使Autoboxing 也无法解决这个难题,因为IntegerString 不处于继承关系中。因此,(String) myInt 导致编译错误是完全合理的。

Integer.toString(myInt)"" + myInt 的语义相同。但是,具体情况有所不同。

在执行Integer.toString(myInt) 时,会构造一个新的String,其中包含myInt 的字符串表示形式。

在执行"" + myInt时,Java首先构造一个全局的String-constant,其值为""(这是由JVM完成的,我们看不到这个1)。词法分析器要求在+ 的右侧有一个String,因为它在+ 的左侧找到了一个String。对于原语,JVM“知道”如何将它们转换为Strings。对于对象,调用toString()。因为Object 有这个方法并且每个类(至少隐式地)派生自Object,所以每个对象都保证有一个toString() 方法。这是构造的第二个String。由于Strings are immutable,JVM 可能会创建第三个String,代表前两个Strings2 的串联。


结语

然后,在执行时,JIT 编译器会发生故障,其中大部分可能无关紧要,因为两个变体的 JIT 优化版本可能看起来相同。或不。或者也许只是有时。 JIT 会做一些有趣的事情。所以说到底还是个人风格的问题,而不是表现的问题:)


1 这其实是个谎言。写的时候

String s1 = "";
String s2 = "";
System.out.println(s1 == s2);

人们会观察到结果是true,而false 是预期的。这是因为 JVM 为所有 String 常量创建了一个池以节省一些内存。

2 JVM 很可能“识别”了something + "" == "" + something == something,因此不会创建第三个String。我没有对此进行测试或研究。

【讨论】:

    【解决方案2】:

    我自己更喜欢String.valueOf(int),但是是的,有多种途径可以到达那里。

    一般来说,如果您要将int 转换为String单独,您需要Integer.toString(int)String.valueOf(int) 或类似的。

    您的"" + myInt 的效率将明显低于上述方法(尽管通常无关紧要):它编译为创建一个新的StringBuilder,然后将"" 附加到它,然后将int 附加到它(它首先调用上述方法之一将其转换为字符串),然后从StringBuilder 获取String。因此,虽然您可以将其作为整体串联操作的一部分来执行,但它本身就很糟糕。

    您的 (String) 示例不起作用:您不能只将 int 强制转换为 String,您将收到编译时“不兼容类型”错误。

    【讨论】:

      【解决方案3】:

      这是一种“正式”重载 + 运算符的语言功能,因此

      "" + myInt
      

      按如下方式编译:

      new StringBuilder().append("").append(myInt).toString();
      

      StringBuilder#append()(最终)调用String.valueOf() 来渲染myInt

      这个功能大概是因为如果他们不这样做,就没有人会使用这种语言——这太痛苦了。

      【讨论】:

      • 重载 + 运算符 - 解释机制。
      【解决方案4】:

      首先,让我们比较一下(String)valval.toString()

      这两个语句的主要区别在于,转换是由编译器进行的,而toString() 方法通常由程序员实现。也就是说,只有当值扩展 String 并且您可以实现任何类的 toString() 时,您才能强制转换。 toString() 与任何其他方法一样工作,没有(几乎)特别之处。

      现在让我们看看""+int。我个人认为这是反模式,因为它被编译成非常低效的代码。创建了很多无用的对象;简而言之:结果类似于手动将几个字符串文字与StringBuilder 连接起来。此外,在 ""+var 等语句中,var 不会扩展 StringtoString() 隐式调用。

      我希望这很清楚。

      【讨论】:

        【解决方案5】:

        (String) - 这仅适用于字符串,所以如果你有这个:

        Object test = "test";
        String test2 = (String) test;
        

        它会起作用(因为Object 测试将是String 类型)。

        如果你有这样的事情:

        Integer test = new Integer(2);
        String test2 = (String) test;
        

        你会得到ClassCastException

        Integer.toString(myInt)
        

        这就是它的作用:

         public static String  toString(int i) {
                 if (i == Integer.MIN_VALUE)
                     return "-2147483648";
                 int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
                 char[] buf = new char[size];
                 getChars(i, size, buf);
                 return new String(0, size, buf);
             }
        

        它只是将您的号码逐个字符地转换为字符串。

        "" + myInt
        

        这将告诉编译器您想将事物作为字符串连接,而不是添加两个数字(因为字符串是第一个,它将与连接字符串一起使用)。 myInt 将被转换为字符串,或者如果它是一个对象,它将从中调用toString() 方法。

        另外,请确保您阅读了有关 JVM 中的字符串池的信息,以了解它在这里会做什么。在这种情况下,它最终可能会创建大量临时字符串(如果您有很多 +;请使用 StringBuilder 避免这种情况)。

        【讨论】:

          猜你喜欢
          • 2011-05-22
          • 2019-10-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-25
          • 2014-01-07
          • 2016-05-20
          • 1970-01-01
          相关资源
          最近更新 更多