Java基础:String类
一、String的特性
1)String类:代表字符串。
2)Java 程序中的所有字符串字面值(如 "abc" )都作为此类的实例实现。
3)String是一个final类,代表不可变的字符序列。
4)字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。 可以共享
5)String对象的字符内容是存储在一个字符数组value[]中的。
字符串常量池补充:
字符串字面常量是存储在字符串常量池中的
jdk1.6-以前 字符串常量池位于方法区的永久代
jdk1.7 字符串常量池位于堆区
jdk1.8+以后 字符串常量池位于方法区的元空间
二、字符串的创建方式
第一种情况
String s="abc";
表示,先在栈上创建一个引用s ,它会先去常量池中看有没有 “abc” 这个常量
如果有,则把字符串常量池中"abc"该字符串的地址返回给当签 s 引用。
如果没有,则在常量池中创建 abc
第二种情况
String s=new String("abc");
相当于 String obj=“abc”; String s=new String(obj) ;
经过这个操作以后,内存中有两份数据: 常量池中一份,堆上一份。由于有了 new 这个操作,不管常量池中原来有没有 “abc” ,它都会在堆上创建一份
三、字符串的比较
例1:字符串常量池的使用
1 String s0 = "abc";
2 String s1 = "abc";
3 System.out.println(s0==s1); //true
4 // s0 和 s1 都指向了常量池中的同一个 "abc"
例2:String中 == 与equals的区别
1 String s0 =new String ("abc"); //new 这个操作,将在堆上产生对象,s0指向了堆
2 String s1 =new String ("abc");
3 System.out.println(s0==s1); //false s0 和 s1 指向的是堆上不同de的对象
4 System.out.println(s0.equals(s1)); //true 因为String类重写了equals方法,比的是实体的内容
== 和 equals的区别
1 == 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型 就是比较内存地址
2 equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过,默认也是 == ;我们可以看到String等类的equals方法是被重写过的,
而且String类在日常开发中用的比较多,久而久之,形成了equals是比较值的错误观点。
3 具体要看自定义类里有没有重写Object的equals方法来判断。
4 通常情况下,重写equals方法,会比较类中的相应属性是否都相等。
例3:编译期确定
1 String s0="helloworld";
2 String s1="helloworld";
3 String s2="hello" + "world"; // 编译的时候,就会完成字面常量的拼接,直接就编译成 helloworld
4 System.out.println( s0==s1 ); //true
5 System.out.println( s0==s2 ); //true
例4:编译期无法确定
1 String s0="helloworld";
2 String s1=new String("helloworld");
3 String s2="hello" + new String("world");
4 System.out.println( s0==s1 ); //false 一个指向常量池,一个指向堆
5 System.out.println( s0==s2 ); //false
6 System.out.println( s1==s2 ); //false
例5 编译期无法确定
1 String s0 = "ab";
2 String s1 = "b";
3 String s2 = "a" + s1; // s1不是常量,编译期无法确定,
// 在字符串拼接时,如果出现变量都会在堆内存分配空间,创建对象
4 System.out.println((s0 == s2)); //false
例7:编译期确定 (final)
1 String s0 = "ab";
2 final String s1 = "b"; //加上final 就变成了常量
3 String s2 = "a" + s1; // 对于两个常量相加,编译器能确定它的值
4 System.out.println((s0 == s2)); //true
四、String类及Integer包装类内存分析
public static void main(String[] args) {
//以下两条语句创建了1个对象。"凤山"存储在字符串常量池中
String str1 = "凤山";
String str2 = "凤山";
System.out.println(str1==str2); //true
//以下两条语句创建了3个对象。"天峨",存储在字符串常量池中,两个new String()对象存储在堆内存中
String str3 = new String("天峨");
String str4 = new String("天峨");
System.out.println(str3==str4); //false
//以下两条语句创建了1个对象。9是存储在栈内存中
//这里所说的一个对象,是指的9 , i 和 j 则是对9的引用
int i = 9;
int j = 9;
System.out.println(i==j);//true
//由于没有了装箱,以下两条语句创建了2个对象。两个1对象存储在堆内存中
Integer l1 = new Integer(1); 注意这里是没有装箱操作的
Integer k1 = new Integer(1);
System.out.println(l1==k1); //false
//以下两条语句创建了1个对象。1对象存储在栈内存中。自动装箱时对于 -128-127之间的值,直接使用。
//在Java中会对常用的小范围的数字-128---127之间的数进行缓存
Integer l = 20;//装箱
Integer k = 20;//装箱
System.out.println(l==k); //true
Integer i1 = 256;
Integer i2 = 256;
//以下两条语句创建了2个对象。i1,i2变量存储在栈内存中,两个256对象存储在堆内存中,因为对于 -128-127 范围之外的值,会创建新的对象
System.out.println(i1==i2);//false
}
Integer i = new Integer(1);
Integer j = new Integer(1);
int z = 1;
System.out.println(i == j); // false
System.out.println(i == z); // true
Integer m = 1;
System.out.println(m == i);// false
1、Integer m=1;java中将1自动装箱成Integer类型,也就是说1已经不是基本数据类型了,变成了对象,也就是引用类型。所以当 m==i 相比较,比较的是地址符,2个对象肯定不相等,所以为false。
2、int z=1;是因为 i 自动拆装为int类型(变成基本类型了)在与z比较,i==z 比较的是数值,所以相等。(一定要记得java的自动装箱 / 拆箱)