String类详解(java)

文章目录

1 -基本概念

2 -常用的构造方法

3 -字符串常量池

4 -常用方法

5 -总结


1 -基本概念

 java.lang.String类由final关键字修饰,表示该类不能被继承。

该类用于描述字符串,使用该类创建的对象可以描述java中的所有字符串字面值;如:“abc” ,"123";

java中规定,双引号括起来的字符串,是不可变的,也就是说“abc”自出生到最终死亡,不可变(重点),不能变成“abcd”

注意 String s1 = null; 与 String s1 = ""; 有何区别?

解释

前面的形式表示没有字符串对象,后面的形式表示有字符串对象但是没有内容。


2 -常用的构造方法

方法名 说明
String() 使用无参的形式构造对象
String(byte[] bytes) 使用参数指定字节数组来构造对象
String(byte[] bytes,int offset,int length) 使用参数指定字节数组的一部分来构造对象

/**
 * @author Mr.乐
 * @data 2022/8/1  22:33
 */
public class Demo3 {
    public static void main(String[] args) {
        byte[] bytes = {97,98,99,100,101,102,103};//定义字节数组
        String s = new String();//创建空字符串对象
        String s1 = null;

        System.out.println(s);//有对象,但是没有内容
        System.out.println(s1);//没有对象 null

        String s2 = new String(bytes);//将参数的byte数组转换成String类型的对象
        System.out.println(s2);//abcdefg
        String s3 = new String(bytes, 4, 3);
        System.out.println(s3);//efg
    }
}

3 -字符串常量池

Java为了避免大量字符串对象,设计了字符串常量池的概念,通过初始化方式创建的字符串都会存储在字符串常量池中,且字符串不能重复,以便共性使用,提高存储效率。

在JDK当中双引号括起来的字符串,例如:“abc”都是直接存储在方法区的字符串常量池当中

如图所示:

使用初始化方式创建字符串对象时String str = "Hello";JVM会先检查字符串常量池中是否存在相同的字符串,如果存在,则直接返回该字符串引用地址,如果不存在,则字符串存放到常量池中并返回字符串引用地址。

图中s1与s2指向一个字符串常量池中的“hello”。例如 String s1="hello",String s2="hello",所以运算符s1==s2为ture

使用new关键字创建对象时,JVM同样会先到常量池中检查字符串是否存在,存在则在内存中创建一个字符串对象并返回对象引用地址,如果不存在,则在常量池和堆中依次创建字符串对象,返回该对象的引用地址。

图中x与y指向不同的堆中的对象,虽然堆中的对象指向字符串常量池中同一个对象,但是堆中两对象内存地址不同,如:String x=new String("xxx"),String y=new String("xxx")所以x==y为false 

所以为了保险起见,我们对比字符串时,会用字符串的equals方法来比较(字符串含有重写的equlas方法,因为字符串属于引用类对象)。不能用Object的equlas方法,Object中的equlas没有重写。

/**
 * @author Mr.乐
 * @data 2022/8/1  22:46
 */
public class Demo04 {
    public static void main(String[] args) {
        //使用初始化的方式创建了两个相同的字符串。
        String s1 = "张三";//第一次创建,字符串常量池中没有,则会创建字符串并返回地址
        String s2 = "张三";//第二次创建,字符串常量池中有,则直接返回该对象的地址。

        String s3 = new String("张三");//在堆中创建对象
        //java把String类的equals方法重写了,可以直接用
        System.out.println(s1.equals(s2));//地址相同,所以true
        System.out.println(s1.equals(s3));//true
    }
}

4 - StringBuffer、StringBuilder

String类型与StringBuffer类型的主要区别在于String类是不可改变的对象,因此,每次对String类型进行改变都想相当于创建一个新的对象,然后将原引用地址指向新的对象,这样不仅效率低,而且浪费大量的内存空间,特别是当内存中没有引用的对象多了以后,JVM中的GC会自动开始工作,程序的运行效率就会大大的降低。

和String类不同的是,StringBuffer和StringBuilder类的对象能够实现被多次修改,并且不产生新的未使用对象。

区别对比

类名 区别
String 值不可变,修改就创建新的对象,占用内存空间大
StringBuffer 值可变,不会创建新的对象,占用内存空间小,线程安全,多线程
StringBuilder 值可变,不会创建新的对象,占用内存空间小,线程不安全,单线程
/**
 * @author Mr.乐
 * @data 2022/8/2  16:59
 */
public class Demo05 {
    public static void main(String[] args) {
        String str = new String("Hello");//原来对象不可改变
        String newStr = str + "Java";//创建新对象
        //System.out.println(str == newStr);//false,说明连个引用指向的不是同一个对象
        //创建StringBuilder对象
        StringBuilder ss = new StringBuilder("Hello");
        StringBuilder newSs = ss.append(" Java");//在原字符串对象中追加字符串
        System.out.println(ss == newSs);//都是针对同一个对象进行操作 ture
        System.out.println(ss);//打印字符串  Hello Java
        ss.append("!~");//表示在原对象基础之上进行追加
        System.out.println(ss);
        ss.insert(10,"SE");//在指定位置插入字符串
        System.out.println(ss);//Hello JavaSE!~
        ss.replace(6,12,"MySql");//用来替换字符串
        System.out.println(ss);
        ss.delete(6,11);//通过指定参数的位置删除字符串
        System.out.println(ss);
        System.out.println(ss.length());//获取字符串长度,8个长度
    }
}

在大量字符串重复拼接时,StringBuilder可以增加拼接效率。

如图为默认拼接100000字符串,耗时1227毫秒

/**
 * @author Mr.乐
 * @data 2022/8/2  17:23
 */
public class String01 {
    public static void main(String[] args) {
        String a="";
        long start=System.currentTimeMillis();
        for(int i=0;i<100000;i++){
            a+="a";
        }
        long end=System.currentTimeMillis();
        System.out.println(end-start);//1227
    }
}

如图为StringBuilder拼接100000字符串,耗时7毫秒

/**
 * @author Mr.乐
 * @data 2022/8/2  17:23
 */
public class String01 {
    public static void main(String[] args) {
        StringBuilder a=new StringBuilder();
        long start=System.currentTimeMillis();
        for(int i=0;i<100000;i++){
            a.append("a");
        }
        long end=System.currentTimeMillis();
        System.out.println(end-start);//7
    }
}

两者效率差别很明显。因为在使用普通字符串拼接时,jvm会在每次拼接的时候new一个StringBuilder对象,那么普通的拼接100000次,就会new100000个StringBuilder对象,相比于使用一个StringBuilder对象拼接,效率就会大大降低。所以在字符串拼接的时候,要使用StringBuilder。


5 -常用方法

方法名 说明
char charAt(int index) 用于根据参数指定的下标返回对应位置的字符
int length() 用于返回字符串长度
int compareTo(String anotherString) 用于按照字典顺序来比较两个字符串大小
int compareToIgnoreCase(String str) 比较字符串的大小,不考虑大小写。
boolean equals(Object anObject) 用于判断调用字符串和参数字符串是否相等
boolean equalsIgnoreCase(String anString) 用于判断是否相等,忽略大小写
contains(CharSequence s) 判断调用字符串中是否包含参数字符串
String concat(String str) 返回参数对象与调用对象的拼接
boolean endsWith(String suffix) 判断当前字符串是否以suffix为结尾
boolean startsWith(String prefix) 判断当前字符串是否以profix为开头
String toLowerCase() 用于将所有字符串转换成小写
String toUpperCase() 用于将所有字符串转换为大写
byte[] getBytes() 用于将字符串内容转换为byte数组并返回
int indexOf(String str) 用于查找指定参数第一次出现的下标,不存在则返回-1
int lastIndexOf(String str) 用于查找指定参数最后一次出现的下标
String substring(int beginIndex) 用于获取从参数指定位置开始的字符串
String substring(int beginIndex,int endIndex) 用于获取从beginIndex位置开始到endIndex位置之间的字符串
import java.util.Arrays;

/**
 * @author Mr.乐
 * @data 2022/8/2  12:42
 */
public class Demo01 {
    public static void main(String[] args) {
        //初始化方式定义字符串
        String str01 = "Hello String";
        String str02 = "hello String";
        System.out.println(str01.charAt(4));//o,起始位置为0
        System.out.println(str01.length());//返回字符串的长度12
        //比较字符串的大小,调用对象与参数对象进行比较 compareTo()
        System.out.println(str01.compareTo(str02));//按照字符编码进行比较
        //-32   H的字符编码 - h的字符编码为32
        System.out.println(str01.compareToIgnoreCase(str02));//忽略大小写 0
        //equals 用于判断调用字符串和参数字符串是否相等 此处为String类的equals方法
        System.out.println(str01.equals(str02));//false
        System.out.println(str01.equalsIgnoreCase(str02));//true,忽略大小写比较字符串内容
        //contains 判断调用字符串中是否包含参数字符串
        System.out.println(str01.contains("String"));//字符串中有String字符串
        System.out.println(str01.contains("string"));//false
        //concat 返回参数对象与调用对象的拼接
        System.out.println(str01.concat("!~")); //Hello String!~
        //endsWith 是否以某字符串为结尾  startsWith 是否以某字符串为开头
        System.out.println(str01.endsWith("ing"));//true
        System.out.println(str01.startsWith("Hello"));//true
        //toLowerCase  toUpperCase
        System.out.println(str02.toLowerCase());//将调用对象的字符串全部变成小写
        System.out.println(str02.toUpperCase());//将调用对象的字符串全部变成大写
        //getBytes
        byte[] bytes = str02.getBytes();
        System.out.println(Arrays.toString(bytes));//[104, 101, 108, 108, 111, 32, 83, 116, 114, 105, 110, 103]
        //indexOf 查找指定参数第一次出现的下标,不存在则返回-1
        //lastIndexOf  用于查找指定参数最后一次出现的下标
        System.out.println(str02.indexOf("t"));//7
        System.out.println(str02.lastIndexOf("l"));//3
        //substring 用于获取从beginIndex位置开始到endIndex位置之间的字符串
        System.out.println(str02.substring(6));//String 从下标为6开始至结束
        System.out.println(str02.substring(6,10));//Stri  前闭后开
    }
}

5 -总结

String类中最重要的是底层的结构,希望大家可以理解底层。方法忘了是可以查文档的,底层做你重要。

猜你喜欢

转载自blog.csdn.net/zdl66/article/details/126112290