Java知识点总结【4】String

1.String的创建

1)String str1="hello"; 

2)String str2=new String("hello"); 

3)通过char[]或者byte[]的方式来构造字符串

char[] arr={'h','e','l','l','o'};
String str3=new String(arr);

其中第一种方式最常用,实际上创建方式很多,不止上面三种,需要的时候再去查~

2.字符串比较相等

1)==比较的是对象的身份(比较两个引用中保存的地址是否相同/比较两个引用是否指向同一个对象)

例①

String str1="hello";
String str2="hello";
System.out.println(str1==str2);

结果

分析:

像"hello"这些字符串字面值常量是存在字符串常量池中,用的时候直接引用到常量池中的hello的位置就行了,保存一份即可,没必要在内存中存储两次。所以我们上面的str1和str2两个引用实际上指向的都是同一个hello对象,所以==比较对象的身份之后,结果为true。

例②

String str1=new String("hello");
String str2=new String("hello");
System.out.println(str1==str2);

结果

分析:

上面代码中,我们使用new 关键字创建了两个对象,让str1和str2分别指向这两个对象。由于指向的是不同的对象,所以==比较之后结果为false。

由此也可以看出,直接赋值的方式创建字符串比较高效,在多次引用内容相同的字符串时,不用去搞那么多对象,字符串常量池中一个就够了。

2)equals方法比较的是两个字符串的内容(只针对String类型)

String str1=new String("hello");
String str2=new String("hello");
System.out.println(str1.equals(str2));//也可写成str2.equals(str1)

结果为true

System.out.println(str1.equals("hello"));
System.out.println("hello".equals(str1));

上面两种方式中,建议写成第二种。由于第一种中str1是引用类型的变量,空引用类型不能解引用,一旦str1是空引用,就会抛出异常,字面值常量就不会涉及到这个问题~

3.字符串常量池

池是一种重要的思想方法,把一些经常使用的对象提前创建好保存起来,以备随时去使用,降低开销,提高效率。

4.将String对象的内容添加到字符串常量池中

使用intern方法

例:

String str1=new String("hello");
System.out.println("hello"==str1);
String str2=new String("hello").intern();
System.out.println("hello"==str2);

结果

分析:

常量池是JVM划分的一个内存区域,JVM一运行的时候就会专门搞一个区域叫做常量池(也是堆的一个部分)

上面的代码中,调用intern()方法,就会拿着当前这个字符串里的内容在字符串常量池中找,看是否存在于常量池中,如果存在,则直接返回该池中的地址;如果不存在,则把当前字符串的内容添加到常量池中,返回池中的地址。

5.字符串不可变

String数组内部持有的char[] value数组的内容不能在类外部发生改变,是封装的体现。

优点:

1)方便放到池中

2)hashCode也不可变

3)线程安全更有保证

6.使用反射机制来修改String的内容

上面我们说了,字符串是不可变对象,如果我们想要改变,那重新创建一个新的就行了。

但是也有一种特殊方法去修改String的内容,使用反射机制。假如你敲我家门,我肯定不开门,但是如果是警察叔叔为了办案的话,破门而入也是合法的~

反射是面向对象程序设计的一个重要特性。

反射和封装是背道而驰的:

1)使用反射往往可能打破封装

2)反射的代码比较复杂,容易出错

3)反射牺牲了编译器自身的一些检查校验机制,更需要程序员人工保证代码的正确性。

7.字符数组,字节数组,字符串之间的相互转换

字符数组/字节数组—>字符串:上面创建字符串的第三种方式~,toString()方法

字符串—>字符数组:toCharArray

字符串—>字节数组:getBytes

例:

//字符数组/字节数组—>字符串
    char[] arr1={'a','b','c'};
    String str1=new String(arr1);
//字符串—>字符数组
    String str2="hello";
    char[] arr2=str2.toCharArray();
//字符串—>字节数组
    String str3="hello";
    byte[] arr3=str3.getBytes();

 

8.字符串比较大小

1)不忽略大小写,结果为一个数 :使用compareTo()方法

String a="Hello";
String b="hello";
System.out.println(a.compareTo(b));

结果

分析:

按照unicode比较,先比较首字符,若首字符相等就继续比下一个;a>b返回大于0的数;a<0返回小于0的数;a==b返回0

在上面的代码中,大写H显然小于小写h(ASCLL码表也可以看出),所以返回的是<0的数

2)忽略大小写,结果为一个数:使用compareToIgnoreCase()方法

String a="Hello";
String b="hello";
System.out.println(a.compareToIgnoreCase(b));

结果

分析:

和上面的规则一样,只不过是忽略了大小写了,也就是大写H和小写h是一样大的,两个字符串一样大,所以返回0

3)忽略大小写,结果为布尔类型:使用equalsIgnoreCase()方法

String a="Hello";
String b="hello";
System.out.println(a.equalsIgnoreCase(b));

结果

分析:

忽略大小写后,俩字符串中的每个字符都一样大,所以返回true

9.字符串包含

使用contains()方法,结果为boolean类型

String a="Hello world java";
String b="java";
System.out.println(a.contains(b));

结果

注意:

上面的代码为例,a.contains(b)看的是a字符串中是否包含b字符串,不能写反了,那结果就不一样了。

10.子字符串起始位置下标

1)从左往右查找子字符串,如果找到返回第一次出现位置的下标:使用indexOf()方法

String a="Hello java java";
String b="java";
System.out.println(a.indexOf(b));

结果

2)从右往左查找子字符串,如果找到则返回第一次出现位置的下标:使用lastIndexOf()方法

String a="Hello java java";
String b="java";
System.out.println(a.lastIndexOf(b));

结果

11.判定字符串以XXX开头/结尾

1)判断以XXX开头:使用startWith()方法,返回结果为boolean类型

用法:在网络编程中,判断某个链接的协议类型

String a="https://www.baidu.com";
String b="https://";
System.out.println(a.startsWith(b));

结果

2)判断以XXX结尾:使用endsWith()方法,返回结果为boolean类型

用法:判定某个文件的类型

String a="a.java";
String b=".java";
System.out.println(a.endsWith(b));

结果

12.字符串替换

1)替换掉字符串中出现的所有子串:使用replaceAll()方法

String a="Hello world world";
String b="world";
System.out.println(a.replaceAll(b,"java"));

结果

2)替换掉字符串中第一次出现的子串:使用replaceFrist()方法

String a="Hello world world";
String b="world";
System.out.println(a.replaceFirst(b,"java"));

结果

13.字符串拆分

使用split()方法

例①按空格分割

String a="Hello world java";
String[] result=a.split(" "); //分割符为空格
for(String x:result){
    System.out.println(x);
}

结果

例②按.分割

String a="Hello.world.java";
String[] result=a.split("\\.");
for(String x:result){
    System.out.println(x);
}

结果

分析:

可以发现,在按照.分割的时候前面多了两个反斜杠\\

regex表示正则表达式,正则表达式中有很多特殊的符号,"."也是其中之一,为了解决这个问题,需要使用“正则表达式”中的转义字符,也就是正则表达式见到"."是当作特殊符号来对待的,而见到"\."才当作是.本身来看待。接下来,Java中的字符串又把\当成Java的转义字符了,为了表示一个原始的\,需要再次转义。最终为"\\."

总的来说,a.split("\\.");涉及到了两次转义,一次是Java中的转义,一次是正则表达式中的转义

14.字符串截取

使用substring()方法

1)截取一个区间[begin,end),前闭后开

String a="Hello world java";
System.out.println(a.substring(6,11));

结果

2)从某个位置开始截取(包含此位置)

String a="Hello world java";
System.out.println(a.substring(6));

结果

15.其他

1)去掉左右空白符:使用trim()方法

String a="    Hello world  ";
System.out.println("["+a.trim()+"]");

结果

注意:空白符包括:空格、换行、回车、制表符、翻页符、垂直制表符...

2)

  • toUpperCase()  //小写字母转大写
  • toLowerCase()  //大写字母转小写
  • intern()              //字符串入池
  • concat()            //字符串拼接,相当于"+"
  • isEmpty()         //判断是否为空白字符串

16.StringBuffer和StringBuilder

StringBuffer、StringBuilder和String是不同的类。上面说了,String类型创建的变量,它所指向的内容具有不可改变性,除非使用特殊方法(反射机制)。但是为了方便修改字符串,所以就引入了StringBuffer类和StringBuilder类,也就是这两个类创建的变量所指向的内容可以修改。

①字符串末尾拼接:使用append()方法

StringBuffer str=new StringBuffer("hello");
for(int i=0;i<5;i++){
    str.append(i);
}
System.out.println(str);

结果

分析:append()方法,就是直接把参数拼接到原来内存的末尾了,如果拼接的内容太多,超出内存的范围,str会自动扩容。

②字符串反转:使用reverse()方法

StringBuffer str=new StringBuffer("hello");
System.out.println(str.reverse());

结果

③删除规定下标范围的子字符串:使用delete()方法,范围是[begin,end)前闭后开

StringBuffer str=new StringBuffer("Hello,java,world");
System.out.println(str.delete(6,11));

结果

④向指定位置插入数据:使用insert()方法

StringBuffer str=new StringBuffer("Hello rld");
System.out.println(str.insert(6,"wo"));

结果

总结StringBuider和StringBuffer:

两个类的相关操作区别不大,上面是对于StringBuffer类操作的举例。

核心区别:StringBuilder 线程不安全,StringBuffer线程安全

猜你喜欢

转载自blog.csdn.net/weixin_43939602/article/details/112851312