JAVA基础笔记之String的创建方式

String类是我们编程中最常使用的类之一,在使用String类的时候,有许多应该注意到的地方。

String类的对象有两种创建方法:

1)     String s1 = "123a";

2)     String s2 = new String("123a");

这两种创建方式有很大的不同。

第一种创建方式:JVM会现在栈中创建引用变量是s1,然后JVM在内存的静态存储区的字符串常量池中搜索与”123a“相等的字符串常量。如果未搜索到,JVM会在栈中创建4个char型的字符,分别为‘1’,‘2’,‘3’,‘a’,之后JVM在堆中创建一个String的对象,对象值为字符数组{‘1’,‘2’,‘3’,‘a’},最后JVM将这个数组放入字符串常量池中,并将s1指向这个对象的地址。如果JVM在字符串常量池中搜索到了”123a“,就会直接将s1指向这个对象的地址。

第二种创建方式:这个创建方式实际上分为两个步骤 1) String object = "123a",这一步流程同上一中创建方式;2)String s2 = new String(object)  这一步JVM会在堆中建立一个String对象,由于字符串常量池中已经保存了”123a“,所以堆中的String对象共享栈中已保存的四个char型值。

从上文我们可以发现两种创建方式的特点:第一种方式会根据字符串常量池中的情况判断是否新建新的对象;

第二种方式不管字符串常量池中是否保存有相同的对象,必然会在堆中新建String对象。


在列举实例之前,先说明一下”==“与equals方法的区别。

在Object类中,equals方式的实现是基于”==“的,所以直接调用Object类的话,

”==“与equals效果是相同的,这两种方法都是基于内存地址的比较。

但是java api中,绝大多数的类(都继承至Object)重写了equals方法,其中包括包装类和String类等。

在String类中,equals比较的是两个String对象的内容(值)


实例1:

		String a = "123a";
		String b = "123a";
		
		System.out.println(a == b); 		//true  String对象具有相同的内存地址
		System.out.println(a.equals(b));	//true  相同的内容(值)

实例2

		String c = new String("123a");
		String d = new String("123a");
		
		System.out.println(c == d);		//false 说明c和d是不同的对象,内存地址也不相同
		System.out.println(c.equals(d));	//true  equals比较的是内容,即使地址不相同也会返回true
实例1中,无论比较两个String对象的内存地址还是值,他们都是相等的。这说明String的第一种创建方式,值相同的String对象引用,都是指向同一个内存地址。实例2中使用第二种创建方式,打印结果说明,每一次创建String对象,不管其值是否相等,都会创建一个新的对象。

实例3

                String a = "123a";
                String e = "12";
                String f = "3a";
                String g = f + h;
                System.out.println(a == g);//false g在编译时会重新分配地址,而不是寻找相加后的相同内容的地址
                System.out.println(a.equals(g));//true a与g的值相等


实例4

                String a = "123a";
                String h = "12" + "3a";
                System.out.println(a == h);  //true  说明h在编译时被看做字符串常量(这是JVM对“+”这个方法进行了优化的结果)

在实例3中,链接两个已存在的String对象,JVM必须新建一个新的String对象,所以即使值相同,新建的String对象的内存地址与字符串常量的内存地址也是不相同的。而在实例4中,虽然h也是通过链接两个String对象创建,但是在程序编译时,JVM对”+“进行了优化,JVM能够将”12“+”3a“看做常量字符串”123a“。而实例3中,由于e和f这两个引用的地址在程序编译期间是不可知的,所以JVM得优化失效,只能以普通对象对待。


实例5

		String a = "123a";
		final String i = "12";
		final String j = "3a";
		String k = i + j;
		System.out.println(a == k);		//true  final修饰符使得对象在程序编译时能够得知对象地址
由于使用了final修饰符,在编译初期i和j两个对象已保存在了字符串常量池中,编译时,JVM能够获得这两个对象的地址,所以i+j等效于”12“+”3a“。

你可能感兴趣的:(JAVA笔记)