String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
String a = new String("ab"); // a 为一个引用
String b = new String("ab") // b为另一个引用,对象的内容一样
if (a == b) // false,非同一对象,比较的是a与b的内存地址
if (a.equals(b)) // true,String中的equals方法是被重写过的,比较的是对象的值
当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。
String aa = "ab"; // 放在常量池中
String bb = "ab"; // 从常量池中查找
if (aa == bb) // true,aa与bb指向常量池中的同一地址
1.不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何操作,其实都是创建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。(String类利用了final修饰的char类型数组存储字符)
1.String不可变但不代表引用不可以变
2.通过反射是可以修改所谓的“不可变”对象
2.常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,会直接返回缓存的引用。
3.final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了系统的安全性
常量池
String str="i"的方式,java 虚拟机会将其分配到常量池中;
堆内存
String str=new String(“i”) 则会被分到堆内存中;
两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象
String str1 = "hello"; //str1指向静态区
String str2 = new String("hello"); //str2指向堆上的对象
String str3 = "hello";
String str4 = new String("hello");
System.out.println(str1.equals(str2)); //true
System.out.println(str2.equals(str4)); //true
System.out.println(str1 == str3); //true
System.out.println(str1 == str2); //false
System.out.println(str2 == str4); //false
System.out.println(str2 == "hello"); //false
str2 = str1;
System.out.println(str2 == "hello"); //true
String不可变;
StringBuilder与StringBuffer都继承自
AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
String中的对象是不可变的,也就可以理解为常量,线程安全;
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
StringBuilder并没有对方法进行加同步锁,所以是非线程安全
的
每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象;
StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获
得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
如果要操作少量的数据用 String
单线程操作字符串缓冲区 下操作大量数据 StringBuilder
多线程操作字符串缓冲区 下操作大量数据 StringBuffer