风也温柔

计算机科学知识库

java 字符串拼接 Java 字符串连接运算符干了什么?

  和其他多数程序设计语言一样,Java 语言允许使用 + 连接两个字符串。

   String name = "stephen";

  当我们将一个字符串和一个非字符串的值进行拼接时,并不会报错:

   String name = "Stephen";

    int age = 25;

  其原因是当 + 运算符左右两边有一个值是字符串时,会将另一个值尝试转化为字符串。

  字符串转换机制

  我们在了解字符串连接运算符前,先了解一下字符串转换机制( )。

  Any type may be to type by .

  如果值 x 是基本数据类型 T,那么在字符串转换前,首先会将其转换成一个引用值,举几个例子:

  我们知道,对于基本数据类型,Java 都对应有一个包装类(比如 int 类型对应有 对象),这样操作以后,每个基础数据类型的值 x 都变成了一个对象的引用。

  为什么这么做?为了统一对待,当我们把基础数据类型转换成对应的包装类的一个实例后,所有的值都是统一的对象引用。

  此时才开始真正进行字符串转换。我们需要考虑两种情况:空值和非空值。

  如果此时的值 x 是 null,那么最终的字符串转换结果就是一个字符串 null;

  否则就会调用这个对象的 () 的无参方法。

  前者很好理解,后者我们一起来看看:

  在 Java 所有的父类 中,有一个重要的方法就是 方法,它返回表示对象值的一个字符串。在 类中对 的定义如下:

   public String toString() {

        return getClass().getName() + "@" + Integer.toHexString(hashCode());

  该方法返回对象的类名和散列码。如果类没有重写 方法,默认就会调用它的父类的 方法,而此时我们的值 x 统一都是对象值,所以一定有 方法可以调用并打印出值(也有个特殊java 字符串拼接,如果调用 返回的值是一个 null 值,那么就会用字符串 null 代替)。

  字符串连接符

  当 + 运算符左右两边参与运算的表达式的值有一个为字符串时,那么在程序运行时会对另一个值进行字符串转换。

  这里需要注意的是 + 运算符同时作为算术运算符,在含有多个值参与运算的时候java 字符串拼接,要留意优先级,比如下面这个例子:

   String a = 1 + 2 + " equals 3";

  变量 a 的结果是 3 3,变量 b 的结果是 12 12。

  有些人这里可能会有疑问,解释一下,第一种情况根据运算优先级是先计算 1+2 那么此时的 + 运算符是算术运算符,所以结果是 3,然后再和 " 3" 运算,又因为 3 + " 3" 有一个值为字符串java 字符串拼接 Java 字符串连接运算符干了什么?,所以 + 运算符是字符串连接运算符。

  在运行时,Java 编译器一般会使用类似 / 这样带缓冲区的方式来减少通过执行表达式时创建的中间 对象的数量,从而提高程序性能。

  我们可以用 Java 自带的反汇编工具 javap 简单的看一下:

  假设有如下这段代码:

   public class Demo {

        public static void main(String[] args) {
            int i = 10;
            String words = "stephen" + i;
        }

  然后编译,再反汇编一下:

   javac Demo.java

  可以得到如下内容:

   Compiled from "Demo.java"

    public class Demo {
      public Demo();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."":()V
           4: return
      public static void main(java.lang.String[]);
        Code:
           0: bipush        10
           2: istore_1
           3: new           #2                  // class java/lang/StringBuilder
           6: dup
           7: invokespecial #3                  // Method java/lang/StringBuilder."":()V
          10: ldc           #4                  // String stephen
          12: invokevirtual #5                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
          15: iload_1
          16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
          19: invokevirtual #7                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
          22: astore_2
          23: return

  我们可以发现,Java 编译器在执行字符串连接运算符所在表达式的时候,会先创建一个 对象,然后将运算符左边的字符串 拼接()上去,接着在拼接右边的整型 10,然后调用 的 方法返回结果。

  如果我们拼接的是一个对象呢?

   public class Demo {

        public static void main(String[] args) {
            Demo obj = new Demo();
            String words = obj + "stephen";
        }
        @Override
        public String toString() {
            return "App{}";
        }

  一样的做法,我们会发现此时 java/lang/.:(Ljava/lang/;) 也就是 调用的是 ( obj) 这个方法,我们查看 类的 方法:

   public StringBuilder append(Object obj) {

        return append(String.valueOf(obj));

  而 .(obj) 的实现代码如下:

   public static String valueOf(Object obj) {

        return (obj == null) ? "null" : obj.toString();

  也就是会调用对象的 () 方法。

  可能到这里大家会有一个疑问:上面不是说字符串转换对于基本类型是先转换成对应的包装类,然后调用它的 方法吗,这边怎么都是调用 的 方法了呢?

  实现方式不同,其实是本质上是一样的,只不过为了提高性能(减少创建中间字符串等的损耗),Java 编译器采用 来做。感兴趣的可以自己去追踪下 包装类的 方法,其实和 的 (int i) 方法的代码是几乎一样的。

  java 字符串拼接_拼接字符 c语言_go 字符串变量拼接

  文章来源:https://www.toutiao.com/article/6843338959053914627/?wid=1676261573389