Java 类型铸造。 (String)、.toString() 和 "" + int 背后的逻辑

Java type casting. Logic behind (String), .toString() and "" + int

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

这些片段有什么区别:

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

是单纯的历史原因,还是另有隐情?
哪种方法合适?

我个人倾向于 String.valueOf(int),但是是的,有多种途径可以到达那里。

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

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

您的 (String) 示例不起作用:您不能只将 int 转换为 String,您将获得编译时 "incompatible types"错误。

"officially" 重载 + 运算符是一种语言功能,因此

"" + myInt

编译为:

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

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

此功能的实现大概是因为如果他们不这样做,就没有人会使用该语言 - 那就太痛苦了。

(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 来避免这种情况)。

如前所述,(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 "knows" 如何将它们转换为 String。对于对象,调用 toString()。由于 Object 有这个方法并且每个 class 是(至少隐含地)从 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 "recognizes" something + "" == "" + something == something 因此不会创建第三个 String。我既没有测试也没有研究这个。

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

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

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

我希望这是清楚的。