前言:
目前同学们对“string创建的对象在哪里”都比较着重,小伙伴们都需要了解一些“string创建的对象在哪里”的相关知识。那么小编在网上汇集了一些有关“string创建的对象在哪里””的相关知识,希望兄弟们能喜欢,看官们快快来学习一下吧!在Java编程中字符串应用最广泛,Java提供了String类创建和操作字符串。String的值是不可变的,这就导致了String每次操作字符串对象都会生成新的对象,这样就会导致效率低下,而且大量浪费珍贵且有限的内存空间。
String是被final修饰的类,不能被继承,不能被修改;String实现了Serializable和Comparable 接口,表示String支持序列化和可以比较大小;String底层是通过char类型的数据实现的,如下图String类源码:
String类是不可变类,一旦创建一个String对象,包含在这个对象中字符序列是不可改变的,直到这个对象被销毁。
举个列子来看一下内存空间有什么变化:
// 通过直接赋值的形式进行实例化 String name = "乔峰"; name = "虚竹"; // 输出结果:虚竹 System.out.println(name); // 通过构造方法实例化String类对象 String username = new String("段誉"); // 输出结果:段誉 System.out.println(username);
来StringTest.class看一下源码:
public class com.saq.day01.main.StringTest minor version: 0 major version: 49 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #1 // com/saq/day01/main/StringTest super_class: #3 // java/lang/Object interfaces: 0, fields: 0, methods: 2, attributes: 1Constant pool: #1 = Class #2 // com/saq/day01/main/StringTest #2 = Utf8 com/saq/day01/main/StringTest #3 = Class #4 // java/lang/Object #4 = Utf8 java/lang/Object #5 = Utf8 <init> #6 = Utf8 ()V #7 = Utf8 Code #8 = Methodref #3.#9 // java/lang/Object."<init>":()V #9 = NameAndType #5:#6 // "<init>":()V #10 = Utf8 LineNumberTable #11 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 Lcom/saq/day01/main/StringTest; #14 = Utf8 main #15 = Utf8 ([Ljava/lang/String;)V #16 = String #17 // 乔峰 #17 = Utf8 乔峰 #18 = String #19 // 虚竹 #19 = Utf8 虚竹 #20 = Fieldref #21.#23 // java/lang/System.out:Ljava/io/PrintStream; #21 = Class #22 // java/lang/System #22 = Utf8 java/lang/System #23 = NameAndType #24:#25 // out:Ljava/io/PrintStream; #24 = Utf8 out #25 = Utf8 Ljava/io/PrintStream; #26 = Methodref #27.#29 // java/io/PrintStream.println:(Ljava/lang/String;)V #27 = Class #28 // java/io/PrintStream #28 = Utf8 java/io/PrintStream #29 = NameAndType #30:#31 // println:(Ljava/lang/String;)V #30 = Utf8 println #31 = Utf8 (Ljava/lang/String;)V #32 = Class #33 // java/lang/String #33 = Utf8 java/lang/String #34 = String #35 // 段誉 #35 = Utf8 段誉 #36 = Methodref #32.#37 // java/lang/String."<init>":(Ljava/lang/String;)V #37 = NameAndType #5:#31 // "<init>":(Ljava/lang/String;)V #38 = Utf8 args #39 = Utf8 [Ljava/lang/String; #40 = Utf8 name #41 = Utf8 Ljava/lang/String; #42 = Utf8 username #43 = Utf8 SourceFile #44 = Utf8 StringTest.java{ public com.saq.day01.main.StringTest(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #8 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 8: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/saq/day01/main/StringTest; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=3, locals=3, args_size=1 0: ldc #16 // String 乔峰 2: astore_1 3: ldc #18 // String 虚竹 5: astore_1 6: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream; 9: aload_1 10: invokevirtual #26 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 13: new #32 // class java/lang/String 16: dup 17: ldc #34 // String 段誉 19: invokespecial #36 // Method java/lang/String."<init>":(Ljava/lang/String;)V 22: astore_2 23: getstatic #20 // Field java/lang/System.out:Ljava/io/PrintStream; 26: aload_2 27: invokevirtual #26 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 30: return LineNumberTable: line 10: 0 line 11: 3 line 13: 6 line 15: 13 line 17: 23 line 18: 30 LocalVariableTable: Start Length Slot Name Signature 0 31 0 args [Ljava/lang/String; 3 28 1 name Ljava/lang/String; 23 8 2 username Ljava/lang/String;}
从文件中可以看出字符串常量池(Constant pool)有两个对象。可以看出,再次给name对象赋值时,并不是对原来堆中实例对象进行重新赋值,而是生成一个新的实例对象,并且指向“虚竹”这个字符串,name则指向新生成的实例对象,之前的实例对象仍然存在,如果没有被再次引用,则会被垃圾回收。
String类对象实例化的方式有两种:
1.通过直接赋值的形式进行实例化
String name = "乔峰";
2.通过构造方法实例化String类对象
String name = new String("段誉");
两种实例化String类对象虽然结果一样,但是本质上有很多区别,通过直接赋值的方式为字符串赋值时,此时的字符串存储在方法区的字符串常量池中;
通过构造器方式实例化字符串时,字符串对象存储在堆中,但是字符串的值仍然存储在方法区的常量池中。
标签: #string创建的对象在哪里