java中创建字符串对象:
1、字面量形式,如String str = "beautiful";
2、使用new这种标准的构造对象的方法,如String str = new String("beautiful");
3、字面量 + 字面量:String str = "hello" + "you";
4、字面量 + 变量:String a = "hello"; String str = a + "you";
java字符串常量池
1、JVM为了减少字符串对象的重复创建,维护了一个特殊的内存,这段内存就是字符串常量池。
2、当代码中出现字面量形式创建字符串对象时,Java运行时(运行中JVM)会在字符串常量池中找是否存在内容相同的字符串对象的引用,如果存在则将引用返回。否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。
3、Java中,只要使用new关键字来创建对象,则一定会在堆区创建一个新的对象。首先查看池中是否有相同值的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制到池中,否则导致浪费池的空间)
4、使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个,有则罢了!但绝不会在堆栈区再去创建该String对象。
5、使用包含变量的表达式来创建String对象,则不仅会检查维护字符串常量池,而且还会在堆栈区创建一个String对象。因为 a 在编译的时候就可以获得,而 str 必须在运行的时候才可以获得对应的值,所以 str 会在堆栈中创建一个新的对象,同时会在字符串常量池中创建两个字符串字面量baby和yesbaby
String a = "yes";
String str = a + "baby";
实例1
参考上面第2条,通过字面量创建的字符串对象,会先去常量池中查找有没有和我这个字面量值一样的,如果有就返回那个对象的引用,没有就创建一个新的添加到字符串常量池。所以两个指向的是同一个对象引用,因此是返回true
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2); //true
System.out.println(str1.equals(str2)); //true
实例2
参考第5条,通过字符串拼接的形式创建字符串对象时,会创建一个新的对象,即 str3 指向堆中的hello,未必是常量池中的hello,而str1是字符串常量池中的对象,所以返回false
String str1 = "hello";
String str2 = "hell";
String str3 = str2 + "lo";
System.out.println(str1 == str3); //false
System.out.println(str1.equals(str3)); //false
实例3
参考上面第3条,通过new创建的都会重新新建一个对象,所以地址肯定不一样,返回false
而使用equals为什么返回的又是true呢?这个我们可以去查看源码,如果一个对象没有重写equals方法,那么这个对象调用的就是Object的equals方法,而Object方法的equals比较的是地址值。但是由于String重写了equals方法,String对象的equals方法判断的是指而不是地址值,所以下面调用equals会返回true。
String str5 = new String("hello");
System.out.println(str1 == str5); //false
System.out.println(str1.equals(str5)); //true
实例4
java的JVM在编译期间就把”abc” + “def”进行拼接了
String str="abc"+"def"; //直接将"abcdef"放入字符串池中
System.out.println(str=="abcdef"); //结果为true
intern
对于new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。
调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。
String str1 = "hello";
String str5 = new String("hello");
String str6 = str5.intern();
System.out.println(str6 == str1); //true
字符串常量池中存放的是引用还是对象?
字符串常量池中存放的是对象引用,不是对象。因为在java中,对象都存放在堆内存中。
字符串常量池的好处就是减少相同内容字符串的创建,节省内存空间。
String s = new String(“abc”) 创建了几个对象?
答: 一个或两个。如果常量池中原来没有 “abc”, 就是两个。如果原来的常量池中存在 “abc” 时,就是一个。但是如果考虑到问题就这一行代码,就是说常量池中没有”abc”。
首先,出现了字面量”abc”,那么去String Pool中查找是否有相同字符串存在,r若不存在,那么就在java Heap中用字面量”abc”首先创建1个String对象
然后new String(“abc”),关键字new又在Java Heap中创建了1个对象,然后调用接收String参数的构造器进行了初始化。最终s的引用是这个String对象
String name=new String(“Java”+”hello”);创建了几个对象?
2个。对于”java”+”hello”,java在编译期间会自己先优化的,会合并成一个对象”javahello”的,然后在字符串常量池中保留,然后new的时候再在堆中创建新的对象。因此共创建了两个对象。