String类

String类

先来看看String类的声明:

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0
    ...
} 

/*
从声明可以看出
1)String类被final关键字修饰,意味着String类不能被继承,并且它的成员方法都默认为final方法;字符串一旦创建就不能再修改。
2)String类实现了Serializable、CharSequence、 Comparable接口。
3)String实例的值是通过字符数组实现字符串存储的。
*/

在Java语言中,所有用双引号引起来的值如“ABC”的字面值,都是String类的对象实例,即使没有使用new关键字;String类位于java.lang包下,是Java语言的核心类,提供了字符串的比较、查找、截取、大小写转换等操作;

关于String类有如下要点:

字符串是常量,它们的值在创建之后不能更改。
字符串缓冲区支持可变的字符串。
因为 String 对象是不可变的,所以可以共享。
字符串效果上相当于是char[]数组,但是底层原理是byte[]字节数组。

字符串常量池

字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性,常量池中一定不存在两个相同的字符串。

上面提到的字符串可以共享是什么意思?

我们知道String是java中比较特殊的类,我们可以使用new运算符创建String对象,也可以直接用双引号(“”)创建字串对象。在Java堆内存中存在着一个用来存储字符串的字符串常量池。 当我们使用双引号创建一个字符串时,首先会在字符串常量池中查找是否有相同值的字符串,如果发现则返回其引用不创建新对象,否则它会在池中创建一个新的字符串,然后返回新字符串的引用。这样就实现了字符串的共享,增加资源利用率。 

               String  s3=new String("xyz");
               String  s4=new String("xyz");
                      s3==s4;  ???
采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有(比如上面的语句)"xyz"这个字符串对象,如果有,则不在池中再去创建"xyz"这个对象了,直接在堆中创建一个"xyz"字符串对象,然后将堆中的这个"xyz"对象的地址返回赋给引用s3,这样,s3就指向了堆中创建的这个"xyz"字符串对象;如果没有,则首先在字符串池中创建一个"xyz"字符串对象,然后再在堆中创建一个"xyz"字符串对象,然后将堆中这个"xyz"字符串对象的地址返回赋给s3引用,这样,s3指向了堆中创建的这个"xyz"字符串对象。s4则指向了堆中创建的另一个"xyz"字符串对象。s3 、s4是两个指向不同对象的引用,结果当然是false。

如果使用new运算符创建字符串,则会强制String类在堆空间中创建一个新的String对象。我们可以使用intern()方法将其放入字符串常量池或从字符串常量池中查找具有相同的值字符串对象并返回其引用, intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。

在我们举例子之前先回顾一个知识点:基本数据类型使用“= =”号进行比较的时候是比较它们的值,而引用类型使用“==”进行比较的时候比较的是它们的引用地址。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K486S1y8-1620827701118)(img/1620824143894.png)]

在内存中的情况:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bylMcaUP-1620827701119)(img/1620824497533.png)]

解释:

   * str1是因为是直接用双引号创建的对象且是第一次创建的,所以底层呢首先会在堆中创建一个byte[]数组,内容如图所示;然后在堆中有一个字符串常量池,将这个byte数组的引用存放在这个常量池中。
   * str2也是直接双引号直接创建的,单因为它不算第一次创建的,所以在字符串常量池中能找到相同值的字符串,故直接在字符串常量池中拿引用赋值给str2.
   * charArry字符数组创建后在堆中如图中所示,因为str3是通过new的方式创建的,故它不会在常量池中查看是否有相同内容的引用,而是直接在堆中创建它的存储空间,再将其内存空间的引用赋值非str3。又因为str3的构造方法带了一个char数组参数,所以这个char[]数组在底层会先转化为byte[]数组,然后把这个byte[]数组的引用赋值为string字符串对象,再将这个字符串对象的引用赋值给str3。

所以这两个用双引号创建出来的String类对象是在常量池中找的引用,而new出来的实例对象并不是在常量池中找的引用,故它们两个方式创建出来的实例对象的引用并不相同。

String中 “+” 连接符

原理:

Java语言为“+”连接符以及对象转换为字符串提供了特殊的支持,字符串对象可以使用“+”连接其他对象。其中字符串连接是通过 StringBuilder(或 StringBuffer)类及其append 方法实现的,对象转换为字符串是通过 toString 方法实现的,该方法由 Object 类定义,并可被 Java 中的所有类继承。

= = 和equals方法的区别

前面已经说过了,= = 比较基本数据类型的时候比较的是它们具体的值,比较引用类型的时候比较的是它们的内存地址;

所以这两个方法的区别是:

    1)对于==,比较的是值是否相等
       如果作用于基本数据类型的变量,则直接比较其存储的 “值”是否相等;
    如果作用于引用类型的变量,则比较的是所指向的对象的地址

  2)对于equals方法,注意:equals方法不能作用于基本数据类型的变量,equals继承Object类,比较的是是否是同一个对象
    如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;
    诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容

详细解释:

 == 比较的是变量(栈)内存中存放的对象的(堆)内存地址,用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行覆盖的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断。String s="abcd"是一种非常特殊的形式,和new 有本质的区别。它是java中唯一不需要new 就可以产生对象的途径。以String s="abcd";形式赋值在java中叫直接量,它是在常量池中而不是象new一样放在压缩堆中。 这种形式的字符串,在JVM内部发生字符串拘留,即当声明这样的一个字符串后,JVM会在常量池中先查找有有没有一个值为"abcd"的对象,如果有,就会把它赋给当前引用.即原来那个引用和现在这个引用指点向了同一对象, 如果没有,则在常量池中新创建一个"abcd",下一次如果有String s1 = "abcd";又会将s1指向"abcd"这个对象,即以这形式声明的字符串,只要值相等,任何多个引用都指向同一对象.
   而String s = new String("abcd");和其它任何对象一样.每调用一次就产生一个对象,只要它们调用。
 也可以这么理解: String str = "hello"; 先在内存中找是不是有"hello"这个对象,如果有,就让str指向那个"hello".

 如果内存里没有"hello",就创建一个新的对象保存"hello". String str=new String ("hello") 就是不管内存里是不是已经有"hello"这个对象,都新建一个对象保存"hello"。

String类中常用的方法

1.String的构造方法

1)String(String original):把字符串数据封装成字符串对象
2)String(char[] value):把字符数组的数据封装成字符串对象
3)String(char[] value, int index, int count):把字符数组中的一部分数据封装成字符串对象

2.String类的获取功能

1)length():获取字符串的长度,即是字符个数
        String str="hello Word !";
	    String str1="helloWord!";
	    System.out.println("str: "+str.length());
	    System.out.println("str1: "+str1.length());
结果:
str: 12
str1: 10
2)charAt(int index):获取指定索引处的字符
        String str="hello Word !";
	    System.out.println("str: "+str.charAt(1));

结果:str: e
3)indexOf(String str):获取str在字符串对象中第一次出现的索引
        String str="hello Word !";
	    System.out.println(str.indexOf("ell"));

结果: 1
4)substring(int start):从start开始截取字符串
        String str="hello Word !";
	    System.out.println(str.substring(1));   

结果:ello Word !
5)String substring(int start,int end):从start开始,到end结束截取字符串。包括start,不包括end
        String str="hello Word !";
	    System.out.println(str.substring(1,4));

结果:ell

3.String判断功能

1)equals(Object obj):比较字符串的内容是否相同
        String str="hello Word !";
	    System.out.println(str.equals("hello Word !"));

结果:   true
2)equalsIgnoreCase(String anotherString):比较字符串的内容是否相同,忽略大小写
        String str="hello Word !";
	    System.out.println(str.equalsIgnoreCase("HELLO Word !"));
结果:true
3)startsWith(String prefix):判断字符串对象是否以指定的字符开头(区分大小写)
        String str="hello Word !";
	    System.out.println(str.startsWith("h"));
结果:true
4)startsWith(String prefix,int toffset):判断字符串对象是否以指定的字符开头,参数toffset为指定从哪个下标开始
        String str="hello Word !";
	    System.out.println(str.startsWith("e",1));
结果:true
5)endsWith(String str):判断字符串对象是否以指定的字符结尾
        String str="hello Word !";
	    System.out.println(str.endsWith("!"));
结果:true
6)isEmpty():判断指定字符串是否为空
        String str="";
	    System.out.println(str.isEmpty());
结果:true

4.String类中的转化方法:

1)toCharArray():把字符串转换为字符数组
        String str = "hello Word !";
		char[] charArray = str.toCharArray();
		System.out.println(Arrays.toString(charArray));
结果:[h, e, l, l, o,  , W, o, r, d,  , !]
2)toLowerCase():把字符串转换为小写字符串
        String str1 = "HELLO WOLRD !";
		String lowerCase = str1.toLowerCase();
		System.out.println(lowerCase);
		
结果: hello wolrd !
3)toUpperCase():把字符串转换为大写字符串
结果:

5.其他常用方法

1)trim():去除字符串两端空格
	    String str = " hello World ! ";
		String trim = str.trim();
		System.out.println(trim);
结果:hello World !
2)split():去除字符串中指定的的字符,然后返回一个新的字符串
        String str = "* hello* World* !";
		String[] split = str.split(" "); //注意它的参数是正则表达式
		System.out.println(split[1]);
结果:hello*
3)subSequence(int beginIndex,int endIndex ):截取字符串中指定位置的字符组成一个新的字符串
        String str = "hello World !";
		CharSequence sequence = str.subSequence(1, 4);
		System.out.println(sequence);

结果:ell
4)replace(char oldChar, char newChar):将指定字符替换成另一个指定的字符
结果:
5)replaceAll(String regex,String replasement):用新的内容替换全部旧内容
结果:
6)replaceFirst(String regex,String replacement):替换首个满足条件的内容
结果:
7)lastIndexOf(String str):返回指定字符出现的最后一次的下标
	      String str = "hello World !";
		  int lastIndexOf = str.lastIndexOf("l");
		  System.out.println(lastIndexOf);
结果:9
8)contains(CharSequence s):查看字符串中是都含有指定字符
	    String str = "hello World !";
		boolean b = str.contains("ell");	
		System.out.println(b);
结果:true
9)concat(String str):在原有的字符串的基础上加上指定字符串
	    String str = "hello World !";
		String concat = str.concat("I am boy !");	
		System.out.println("str: "+str);
		System.out.println("concat: "+concat);
结果:
str: hello World !
concat: hello World !I am boy !
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值