在c/c++的学习中我们接触到了字符串,但是在c中其实并没有字符串类型我们写的字符串是char arr[]这样子,其实这个严格来说应该叫字符指针因此其实他并不是字符串类型,而想要操作字符串需要用到库函数或者自己写的函数这并不符合面向对象的思想因此java中创造了String类。
常用的构造方法主要有三个
public static void main(){
String arr="hello";
char[] a={'h','e','l','l','o'};
String arr2=new String(a);
Strin arr3=new String(arr);
}
常见的基本上就是以上三种第一种是直接使用等号,第二种则是使用字符数组,第三种直接利用已有的String对象new一个拷贝一个新的String对象。
此外要主要,String是一种引用类型他的内部存储的是地址而不是字符串。这一点我们怎么证明呢?请看下面的String类的比较
刚刚我们提到String类是引用类型,它内部其实存储的是内存地址我们如何证明这个结论呢?我们来看看下面一段代码
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
String str=new String("abcd");
String str2=new String("abcd");
System.out.println((str==str2));
}
}
这段代码打印出来的内容应该是什么呢?我们分情况来讨论。
首先这个代码都是new一个相同内容的对象,因此我们可以知道这两个对象内部存储的内容是相同的但是地址一定不同因此如果说String对象内部是直接存储的内容的话用等于判断结果应该是true否则如果是地址的话应该是false
而以上代码的最终结果也是false这其实就已经说明了他的内部存储的是地址而并非内容。而String内部的变量的关系如图
注意这里的内部实际关系中我们是可以看到一个String对象其内部还有一个value对象这个value对象指向内容。这里我们可以看一下源代码
可是我们在实际比较的过程中肯定是不希望比较的是地址而是希望以内容作为比较的,那么这个问题该怎么解决呢?其实String‘类的内部重写了equals方法我们在比较的时候其实使用这个方法进行比较的。
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
String str=new String("abcd");
String str2=new String("abcd");
System.out.println((str.equals(str2)));
}
}
而当我们使用equals进行比较时就可以发现最后的结果时正确的了,但是我们会发现这样一个事情那就是当一个char[]类型和一个String类型的内容相同时返回的确实false这是为什么呢?
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
String str=new String("abcd");
String str2=new String("abcd");
char[] arr={'a','b','c','d'};
System.out.println((str.equals(arr)));
}
}
原因就要从equals的底层说起了我们来看一下equals的底层代码
我们看一下equals的底层就会发现这里呢会有两个判断首先第一个就是this==anObject以及anobject instanceof String这里是什么意思呢?首先第一个if就是比较传进来的这个参数是不是自己本身那么这里我们传入的是一个char[]很明显第一个if进不去那么第二个if什么意思呢?第二个if的意思就是传进来的对象是不是String类对象很明显也不是那么最终返回的肯定就是false了
字符串的查找,String中我们想要单独的拿出来一个字符无法像char[]那般直接进行,[下标的方式]那么我们该如何呢?字符串的查找String类用了一系列的方法其中最重要的一个是charAt()方法用法如下
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
String str=new String("abcd");
for(int i=0;i<str.length();i++){
System.out.println(str.charAt(i));
}
}
}
他的使用和下标的使用是一样的。
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
String str=new String("abcd");
String str2=String.valueOf(10010);
System.out.println(str2);
}
}
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
//String str=new String("abcd");
String str2=String.valueOf(10010);
int a=Integer.parseInt(str2);
System.out.println(a);
//System.out.println(str2);
}
}
使用一个新的字符串替换掉原来的字符串,这里我们要知道一个概念就是字符串的不可变性。
字符串的不可变性是指字符串在创建之后字符串的内容事不能在被改变的,换句话说字符串一旦呗创建他的内容就不能在被改变了任何一个尝试修改字符串的手段本质上来说都是用一个新的字符串替换 掉原有的字符串。
由此我们再来看替换字符串的两个函数我们也应当能够明白字符串的不可变性是的所有的替换其实都是不改变原有内容而是重新创建一个字符串
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
//String str=new String("abcd");
String str2=new String("abcd");
//int a=Integer.parseInt(str2);
//System.out.println(a);
//System.out.println(str2);
String str3=str2.replaceAll("a","p");
System.out.println(str2);
System.out.println(str3);
}
}
因此我们可以看出来这个字符串中str2的内容是没有被改变的只是重新返回了一个字符串并赋值给了str3
字符串的拆分是指将一个字符串中的某个字符作为分割字符从而将一个字符串拆分为多个子串。拆分的方法是split。我给大家演示一下
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
//String str=new String("abcd");
String str2="https:editor.csdn.netmd?not_checkout=1&spm=1001.2014.3001.4503&articleId=136138248";
String[] str3=str2.split("\\.");
System.out.println(str2);
for(String s:str3){
System.out.println(s);
}
}
}
这里是以"."为分割符进行分割的。此外还有别的用法比如说你可以设定拆分几组
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
//String str=new String("abcd");
String str2="https:editor.csdn.netmd?not_checkout=1&spm=1001.2014.3001.4503&articleId=136138248";
String[] str3=str2.split("\\.",2);
System.out.println(str2);
for(String s:str3){
System.out.println(s);
}
}
}
此外我们还可以多次拆分
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
//String str=new String("abcd");
String str="zyf=icl,cl=izyf";
String[] str2=str.split("\\,");
for(int i=0;i<str2.length;i++){
String[] str3=str2[i].split("=");
System.out.println(str3[0]+" = "+str3[1]);
}
}
}
字符串截取一般都是用于我们想使用某个区间内的内容,所需要的函数是String substring(int beginIndex)
他的用法如下
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
//String str=new String("abcd");
String str="zyf=icl,cl=izyf";
String str2=str.substring(2);
System.out.println(str2);
}
}
当只输入一个参数的时候它表示从改下标一直到结尾位置。
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
//String str=new String("abcd");
String str="zyf=icl,cl=izyf";
String str2=str.substring(2,3);
System.out.println(str2);
}
}
当输入两个参数的时候他表示的是一个左闭右开的区间内容正如实例中会输出f一样表示的是左闭右开
上面我们讲过字符串是不可变的任何对于字符串的修改严格来说都是重新创建了一个对象在进行修改这使得字符串的修改效率非常的慢因此我们一般都是不对字符串的内容做修改的可是在实际开发中肯定是会遇到一些时候是需要对字符串的内容做修改的地方的那么这时候怎么办呢?
我们通常都是借助StringBuilder和StringBuffer
在先讲StringBuilder和StringBuffer之前呢我们先说一下来看一下下面这个代码
public class Main {
public static void main(String[] args) {
//String str=new String("abcd")
String str=new String();
for(int i=0;i<100;i++){
str+=i;
}
System.out.println(str);
}
}
这段代码就很简单就是每一次都在这个字符串后面拼接,那么这个效率低嘛?显而易见很低很低,那么这是为什么呢?因为我们上面说了因为他会创建新的对象那么创建新的对象创建的是什么对象呢?其实是StringBuilder对象,也就是说其实每一次 的改变都会创建一个StringBuilder对象来接受改变的字符串,那么我们如果直接使用StringBuilder实例化出一个对象然后再不断调用append方法效率会不会持续提升呢?很明显是肯定的。
// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
public static void main(String[] args) {
//String str=new String("abcd")
String str=new String();
StringBuilder stringBuilder=new StringBuilder();
for(int i=0;i<100;i++){
stringBuilder.append(i);
}
str=stringBuilder.toString();
System.out.println(str);
}
}
因为我们刚刚讲了为什么效率低下?因为总是创建新的对象那如何增高效率呢?很明显直接降低实列化对象的次数就好了,因此我们直接将StringBuilder定义出来并且直接使用StringBuilder去修改然后将StringBuilder赋值给String即可。
那么StringBuffer是什么呢
StringBuilder:
StringBuilder 是在 Java 5 中引入的,它是非线程安全的。
因为不需要考虑线程安全问题,所以 StringBuilder 的性能比 StringBuffer 更高。
StringBuilder 的方法不是线程安全的,如果在多线程环境中使用,可能会导致数据不一致或者其他问题。
StringBuffer:
StringBuffer 是在 Java 1.0 中引入的,它是线程安全的。
由于需要考虑线程安全性,StringBuffer 的性能通常比 StringBuilder 差一些。
StringBuffer 的方法是线程安全的,可以在多线程环境中安全地使用。
在大多数情况下,如果不需要考虑线程安全性,推荐使用 StringBuilder,因为它的性能更好。只有在需要在多线程环境中安全地操作字符串时才使用 StringBuffer。
学会向爱人妥协才能收获幸福的争吵少的生活,你和爱人是要一起面对生活的而不是你们在互相较劲。