被final修饰就意味着不能被继承,String就不存在子类,这样的就能保证没有覆写,无论哪个人使用的String都是相同的,就可以保证String类下的方法都是相同的。
举个例就是:A使用的String.equals 和 B使用的String.equals完全相同。
什么时候会用到final修饰类?
你的这个类不希望有别的版本,到此为止。所有使用者用的这个类完全相同,没有别的实现。
// 1.直接赋值
String str1 = "Hello world";
// 2.通过构造方法产生对象
String str2 = new String("Hello world");
// 3.通过字符数组产生对象
char[] ch = {'H','e','l','l','o',' ','w','o','r','l','d'};
String str3 = new String(ch);
// 4.通过String的静态方法 valueOf(任意数据类型) 转为字符串
String str4 = String.valueOf(100);
关于字符串的字面量
什么叫字面量哪?字面量可以简单的理解为直接写出来的数值。比如:
10 就是 int类型的字面量;
10.1 是 double类型的字面量;
true 是 boolean 类型的字面量;
"abcd" 是 String类型的字面量
在这些例子中 String有比较特殊,因为String类型是引用数据类型,所以String类型的字面量本身就是一个字符串对象。那因为字面量本身就是一个字符串对象,这个时候就会抛出一个有趣的问题,试想以下代码段的结果会是什么?
String str = "hello world";
String str0 = str;
str0 = "Hello";
System.out.println(str);
容我在这里小小的留下一个伏笔。
关于字符串的比较引用数据类型在比较是否相等时,使用 equals方法比较,需要注意的是equals区分大小写的。
当然也有不区分大小写的比较方法 equalsIgnoreCase 。在JDK常用类中,都已经覆写了equals方法,可以直接使用即可。
// 字符串的比较
String str1 = "Hello world";
String str2 = "Hello world";
System.out.println(str1.equals(str2));
关于字符串常量池问题
当使用直接赋值法产生字符串对象时,JVM会维护一个字符串的常量池,若该对象在堆中还不存在,则产生一个新的字符串对象加入字符串的常量池中。
当继续使用直接赋值法产生字符串对象时,JVM发现该引用指向的内容在常量池中已经存在了,则此时不再新建字符串对象,而是复用已有对象。
我们知道引用数据类型使用 “ == " 比较的仍然是地址是否相等,那么下边的代码的结果是什么?
String str1 = "Hello world";
String str2 = "Hello world";
System.out.println(str1 == str2);
String str1 = new String("Hello world");
String str2 = new String("Hello world");
System.out.println(str1 == str2);
注意!!!
此时同时创建了两个 "Hello world",一个在字符串常量池中,另一个在堆上!!!
手动入池方法:String类提供的 intern方法。
调用intern方法会将当前字符串引用指向的对象保存到字符串常量池中有两种情况。
a.若当前常量池中已经存在了该对象,则不再产生新的对象,返回常量池中的String对象
b.若当前常量池中不存在该对象,则将该对象入池,返回入池后的地址。
String str = "Hello";
str += "world";
str += "!!!";
System.out.println(str);
所谓的字符串不可变指的是字符串对象的内容不能变,而不是字符串引用不能变。
这里的不可变指的"hello" "world" "helloworld" "!!!" "helloworld!!!" 这些字符串对象一旦声明后就无法修改其内容。·
哪为何字符串的对象无法修改内容而其他类的对象能修改内容?
字符串其实就是一个字符数组 ---> char[ ],字符串保存的值实际上在数组中保存。我们来看下源码:
这里被private修饰,而且String类内部也没有提供get和set方法以供外部调用。所以String类外部根部就无法拿到这个数据,对于外部而言也就自然无法使用value。
学习了字符串的不可变性,自然而然的会想如果需要那怎么修改字符串的内容呢?
如何修改字符串的内容?一共两种方法:
a.在运行时通过反射破坏value数组的封装(了解,不推荐)
b..更换使用StringBuilder或者StringBuffer类 -----这里和String已经不是一个类了。(若需要频繁进行字符串的拼接,使用StringBuilder类的append方法)
StringBuffer sb = new StringBuffer();
sb.append("Hello");
sb.append("world");
sb.append("!!!");
System.out.println(sb);
使用StringBuffer类的操作和StringBuilder完全一致,不过StringBuffer类是线程安全的,但是性能相对差一点。
关于StringBuilder类的具体使用:
StringBuilder类和String类是两个独立的类,StringBuilder就是为了解决字符串拼接问题产生的。
因为String的对象无法修改内容,为了方便字符串的拼接操作,产生了StringBuilder类,StringBuilder类的对象是可以修改内容的。
// StringBuilder --> String
StringBuilder sb1 = new StringBuilder("Hello");
sb1.append(123);
// String --> StringBuilder
String str = sb1.toString();
a.字符串反转操作,sb提供的 reverse();
b.删除指定范围的数据 delete(int start,int end): 删除从start索引开始end之前的所有内容。[start,end) 左闭右开。
c.插入操作 insert(int start,各种数据类型): 将新元素插入当前sb对象,插入后新数值的起始索引为start
a.String、StringBuilder、StringBuffer的区别:
1.String的对象无法修改,俩sb的对象内容可以修改。
2.StringBuffer是线程安全的操作,性能较差;StringBuilder是线程不安全,性能较高。
b.要使用String类,就采用直接赋值的方式。要比较内容是否相等使用equals方法
c.字符串不可变指的是字符串对象的内容不能变,而不是字符串引用不能变。



