导言
String是我们学习Java最常用的类型之一
从输出“Hello,world”开始,我们就离不开它了
那么,你真的了解它吗?它是引用数据类型还是基本数据类型?字符串可不可以改变?……
面试题
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2);
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2);
String s1 = "abc";
String s2 = "ab";
String s3 = s2 + "c";
System.out.println(s1 == s3);
String s1 = "abc";
String s2 = "a" + "b" + "c";
System.out.println(s1 == s2);
//下面语句创建了几个对象?
String s = new String("abc");
答案在最后,先看解析,再想结果,最后看答案哦,我们都是好宝宝 TAT
概述
String类代表字符串,Java程序中所有字符串文字都被实现为此类的实例。
也就是说,Java程序中所有的双引号字符串,都是String类的对象
String s = new String("abc");
一共创建了两个对象:
- “abc”
- s
String不能用==去比较,用equals进行比较
因为String重写了equals方法(没有重写该方法的equals,还是会比较地址值)
大致比较步骤是:将其转换成char数组,一个一个比较
String的数据类型
结论:
String是引用数据类型还是基本数据类型,取决于它的创建方式,一般认为其是特殊的引用数据类型
众所周知,Java的数据分两类:引用数据类型、基本数据类型
其中引用数据类型一般是类、数组、接口等
只是String比较特殊,因为它既可以是单纯的字符串,也可以是一个对象被new出来
例如:
String s = new String();
System.out.println("Hello,world");
那么怎么检验呢?
有一个方法:利用==运算符
==运算符比较基本数据类型时,是比较真实值;比较引用数据类型时,是比较地址
根据这个原理,你会发现String就像雌雄同体的动物似得,可攻可受、可引用可基本
因为String有多种赋值方式:
- String s = new String()
- String s = new String(char[ ] chs)
- String s = new String(byte[ ] bys)
- String s = “abc”;
- String s = new String(“abc”)
堆内存开辟空间,去常量池中找对应的字符串
若常量池中有,则复制常量池中该字符串的地址,放到堆内存中
若常量池中没有,则先在常量池中创建,然后再复制地址到堆内存
即 new的String永远是指向堆内存
- String s2 = new String(ch)
根据字符数组去创建字符串,同样是执行堆内存 - String s1 = ”abc"
若常量池有,指向常量池;若常量池没有,则创建后指向常量池
直接指向常量池
当比较s1和s时,会发现,虽然s1和s都是“abc”,但是一个指向堆内存,一个指向常量池,故不会相等
面试题答案
String s1 = "abc";
String s2 = "abc";
System.out.println(s1 == s2);
//true
//s1和s2均指向常量池中"abc"的地址
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2);
//false
//s1指向常量池中的"abc",s2指向堆内存
String s1 = "abc"; //指向常量池中“abc”的地址
String s2 = "ab"; //指向常量池中“ab”的地址
String s3 = s2 + "c"; //指向堆内存中String的地址
System.out.println(s1 == s3);
//false
/**先在堆内存中创建StringBuilder对象
通过该对象的append方法,完成字符串的拼接
再调用toString方法,将StringBuilder类型转换成String类型
s3指向Sting类型的堆内存地址
字符串的 + 号拼接非常消耗内存*/
String s1 = "abc";
String s2 = "a" + "b" + "c";
System.out.println(s1 == s2);
//true
//因为+连接的是常量,所以,根据常量优化机制
//s2会和s1指向同一个地方:常量池中“abc”的地址
//下面语句创建了几个对象?
String s = new String("abc");
//两个,因为“abc”也是一个对象