Java中String显式声明的对象创建问题

转载请注明出处:http://blog.csdn.net/infant09/article/details/77822913

关键词:java; String; 字面量; 显式; 声明; 对象; 显示; 直接声明; 直接定义

String对象的几种创建方式


String类是Java中比较特殊的一类。Java在设计时为了提高String类的使用效率,使用String Pool的机制进行String管理。

String对象有以下几种声明方式:

  • 显式声明(使用字面量创建对象,String literals):

    String s = "abc";
  • new关键字声明:

    //通过String创建新的String对象,此方法是redundant
    String s0 = new String("123");
    
    //通过char数组来生成String
    char c[] = {48, 49};
    String s1 = new String(c);
    
    //通过int来生成String
    int i = 123;
    String s2 = String.valueOf(i);
    
    //other function ......
  • 字符串拼接(使用字面量创建对象):

    String s = "123" + "456";

问题提出


通过new关键字声明,实际上是调用了String类的构造方法。但是通过双引号进行显式声明,是如何创建对象的呢?

Java的基本类型,可以直接显式声明,但是String不是基本类型,显然是编译器隐藏了一些细节。

问题解决


String源码

通过阅读String类的源码,可以发现这样一段话:

 * <blockquote><pre>
 *     String str = "abc";
 * </pre></blockquote><p>
 * is equivalent to:
 * <blockquote><pre>
 *     char data[] = {'a', 'b', 'c'};
 *     String str = new String(data);
 * </pre></blockquote><p>

因此我们可以得知,当使用String str = "abc"声明时,等价于首先创建了char数组,然后调用new String的构造方法。

当然,这只是“等价于”(equivalent),编译器做了一些处理。显式调用String str = "abc"和调用char data[] = {'a', 'b', 'c'}; String str = new String(data);是不一样的过程。

bytecode理解

  1. 显式调用

    package Test;
    
    public class StringTest {
    
        public static void main(String[] args) {
            String s = "abc";
        }
    }

    使用$ javap -c StringTest.class查看编译后的class文件:

    public class Test.StringTest {
    public Test.StringTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
    
    public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String abc
       2: astore_1
       3: return
    }
    

    根据字符串池(String Pool)的机制,String str = "abc"会先在常量池里的字符串池查找"abc"对象,如果没有则创建;然后在栈(stack)中创建str引用,直接指向String pool中的"abc"对象。

  2. new关键字声明

    package Test;
    
    public class StringTest {
    
        public static void main(String[] args) {
            char c[] = {'a', 'b', 'c'};
            String s = new String(c);
        }
    }
    

    字节码如下:

    public class Test.StringTest {
    public Test.StringTest();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
    
    public static void main(java.lang.String[]);
    Code:
       0: iconst_3
       1: newarray       char
       3: dup
       4: iconst_0
       5: bipush        97
       7: castore
       8: dup
       9: iconst_1
      10: bipush        98
      12: castore
      13: dup
      14: iconst_2
      15: bipush        99
      17: castore
      18: astore_1
      19: new           #2                  // class java/lang/String
      22: dup
      23: aload_1
      24: invokespecial #3                  // Method java/lang/String."<init>":([C)V
      27: astore_2
      28: return
    }
    

    可以首先在堆(heap)中创建对象,然后调用String类的构造方法。当然,调用构造方法的过程中,会在String pool里查找或创建"abc"对象,然后再根据这个对象去heap中创建对象。

这就是显式声明字符串的过程。

其他问题

  • 字符串常量池究竟在JVM的哪里?
  • String s = new String(“abc”) + “abc”,创建了多少个对象?以及其他类似问题

参考文献

https://tech.meituan.com/in_depth_understanding_string_intern.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2023年5月29日 学习要点 理解继承的概念,超类和子类的关系,掌握它们在继承的应用; 掌握类有关private成员的访问控制方法; 理解方法重载和方法重写的区别和使用方法; 第1页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第1页。 2023年5月29日 4.1 包 包是由.class文件组成的一个集合 第2页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第2页。 2023年5月29日 4.1.1 定义包 构建包语句的语法是: package pkg1[.pkg2[.pkg3…]]; 例如:package com.javaworld; package语句作为Java源文件的第一条语句。如果没有package语句,则为缺省无名包。 则该语句的前面只能有注释或空行。而且一个文件最多有一条package语句。 包名有层次关系,全部用小写字母,各层之间用点分割. 第3页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第3页。 2023年5月29日 包是类的容器,用于分割类名空间。 如果不指定,默认就存在当前文件夹里面。 当使用包说明时,程序不需要再引入同一个包或者该包的任何元素。 如果包声明是: package com.sun.java; 则此文件必须存放在Windows的com\sun\java目录下。 第4页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第4页。 2023年5月29日 包名必须唯一 主要是为了交流,和便于大家的协同合作。 一个使用较多的办法是反转域名,如 com.sun.util; 包名的解释 Java解释器的执行顺序是:首先找到环境变量classpath,利用classpath包含的一个或者多个目录,把他们作为一种特殊的"根"使用,从这里开始搜索,搜索时会把"."替换成"\"(Windows)。 第5页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第5页。 2023年5月29日 4.1.2 导入包 import的语法是: import pkg1[.pkg2[.pkg3…]].(类名" * ); 例如:import java.awt.*; 引入整个包时,可以方便的访问包的每个类。 但是引入所有的包会占用过多的内存。因此,我们建议只引入需要的类。 程序不一定有引入语句。当需要引用某个类与当前类存储在一个物理目录下的时候,就可以直接使用,而不需要引入。 第6页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第6页。 2023年5月29日 4.1.3 类路径(CLASSPATH) 编译时:javac –d CLASSPATH路径 Myclass.java 例如:javac –d d:\Myjava myclass.java 则直接在d:\Myjava创建在myclass.java指明的包目录,并把myclass.class拷到该目录下。 运行:java 包名.类名    如  java   pk1.pk2.类名A 示例 CircleDemo2.java 第7页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第7页。 2023年5月29日 jdk常用的包 java.lang----包含一些Java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能。 java.awt----包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。 java.applet----包含applet运行所需的一些类。 java.net----包含执行与网络相关的操作的类。 java.io----包含能提供多种输入/输出功能的类。 java.util----包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数。 第8页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第8页。 2023年5月29日 4.1.4 访问控制 第9页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第9页。 2023年5月29日 4.2 继承 面向对象的编程允许从现有类派生出新类,这称为继承。 使用继承,程序员可以创建一个定义了多个相关项目共有特性的通用类,然后,其它较为具体的类可以继承该类,同时再添加自己的独有特性。 在Java定义的每一种类都是从现有类派生来的,或者是显式或者是隐式(如从Object类派生) 第10页/共41页 java期末复习第讲面向对象程序设计全文共41页,当前为第10页。 2023年5月29日 11 4.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值