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 也无法解决这个难题,因为 Integer
和 String
不处于继承关系中。因此,(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
。由于 String
s are immutable,JVM 可能会创建第三个 String
,表示前两个 String
s2.
的串联
结语
然后,在执行时,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)val
和val.toString()
。
这两个语句的主要区别在于,转换是由编译器进行的,而toString()
方法通常由程序员实现].也就是说,只有在值扩展 String
时才可以进行转换,并且可以实现任何 class 的 toString()
。 toString()
就像任何其他方法一样工作,没有什么(几乎)特别之处。
现在让我们来看看""+int
。我个人认为这是反模式,因为它被编译成极其低效的代码。创建了许多无用的对象;简而言之:结果类似于手动将几个字符串文字与 StringBuilder
连接起来。此外,在 ""+var
等语句中,var
不扩展 String
,toString()
隐式调用。
我希望这是清楚的。
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 也无法解决这个难题,因为 Integer
和 String
不处于继承关系中。因此,(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
。由于 String
s are immutable,JVM 可能会创建第三个 String
,表示前两个 String
s2.
结语
然后,在执行时,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)val
和val.toString()
。
这两个语句的主要区别在于,转换是由编译器进行的,而toString()
方法通常由程序员实现].也就是说,只有在值扩展 String
时才可以进行转换,并且可以实现任何 class 的 toString()
。 toString()
就像任何其他方法一样工作,没有什么(几乎)特别之处。
现在让我们来看看""+int
。我个人认为这是反模式,因为它被编译成极其低效的代码。创建了许多无用的对象;简而言之:结果类似于手动将几个字符串文字与 StringBuilder
连接起来。此外,在 ""+var
等语句中,var
不扩展 String
,toString()
隐式调用。
我希望这是清楚的。