Java——常用类String及常用方法(超全详细分析)一文掌握String

目录

  • String类特点
    • String类型不能被继承,因为String是由final修饰的
    • String类型的对象是不可变的
      • 常量池
      • 字符串常量池在哪里?
      • String对象为什么不可变?
  • String对象创建个数与拼接结果
    • 对象创建
    • 拼接
    • 空字符串
  • String对象的比较
  • String类常用方法
    • 方法系列一
    • 方法系列二:和char相关
    • 方法系列三:和byte相关
    • 方法系列四
    • 方法系列五:和查找有关
    • 方法系列六:截取
    • 方法系列七:匹配原则(正则表达式)
    • 方法系列八:替换
    • 方法系列九:拆分

java.lang.String

String类特点

String类型不能被继承,因为String是由final修饰的

String类型的对象是不可变的

换句话说,只要修改字符串,就会产生新对象

 @Test
    public void test01(){
     
        String s  = "Hello";
               s.toUpperCase();//将小写字母变为大写字母

        System.out.println(s);//Hello

        s=s.toUpperCase();//s.toUpperCase();这步操作是生成了一个新的String对象"HELLO",
                          // 必须将s重新指向这个新对象,才能实现"修改"原字符串的效果
        System.out.println(s);//HELLO
    }

总结:如果要实现修原字符串的效果,一定要将原来String对象重新赋值,即指向一个新的对象。

常量池

String对象不可变的特性,使得我们可以把一些字符串存到常量池中——字符串常量池。常量池中的数据是可以共享的。

@Test
	public void test02(){
     
		String s1 = "hello";
		String s2 = "hello";		
		System.out.println(s1 == s2)//true;
		//地址是同一个
	}

字符串常量池在哪里?

Oracle官方虚拟机HotSpot
(1)JDK1.6以及之前:方法区
(2)JDK1.7:挪到堆中,即在堆中单独划分了一块来存字符串常量
(3)JDK1.8:从堆中挪出,挪到一个“元空间meta space”,即类似于方法区

String对象为什么不可变?

①底层char[]数组有final修饰,意味着这个数组不能扩容等,来达到存储更多的字符。——无法扩容

②char[]数组是私有的,我们无法直接操作这个char[]数组,而且String没有提供这样的方法,来修改char[]数组的元素的值。——无法修改

部分源码:

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


//无参构造函数,默认创建一个空字符串
 public String() {
     
        this.value = "".value;
    }

public String(String original) {
     
        this.value = original.value;
        this.hash = original.hash;
    }

... ... 
}

String提供的所有的方法,对字符串的修改都是返回一个新的字符串对象。

String对象创建个数与拼接结果

对象创建

String str = "hello";//一个字符串对象

栈中存储的是常量池中char[]的地址。
Java——常用类String及常用方法(超全详细分析)一文掌握String_第1张图片


String str = new String("hello");//两个字符串对象

一个在常量池中:hello。另一个在堆中,String的对象
堆中的这个字符串对象char[]的value数组,指向常量池中"hello"的char[]的value

栈中存储的是堆中对象的地址

Java——常用类String及常用方法(超全详细分析)一文掌握String_第2张图片

拼接

拼接的结果在堆还是在常量池?
(1)常量 + 常量在常量池
(2)变量 +常量在堆
(3)变量 + 变量在堆
(4)xx.intern():在常量池

@Test
	public void test06(){
     
		String s1 = "hello";
		String s2 = "world";
		String s3 = "helloworld";
		
		String s4 = (s1 + "world").intern();//把拼接的结果放到常量池中
		String s5 = (s1 + s2).intern();
		
		System.out.println(s3 == s4);//true
		System.out.println(s3 == s5);//true
	}
	
	@Test
	public void test05(){
     
		final String s1 = "hello";
		final String s2 = "world";
		String s3 = "helloworld";
		
		String s4 = s1 + "world";//s4字符串内容也helloworld,s1是常量,"world"常量,常量+ 常量 结果在常量池中
		String s5 = s1 + s2;//s5字符串内容也helloworld,s1和s2都是常量,常量+ 常量 结果在常量池中
		String s6 = "hello" + "world";//常量+ 常量 结果在常量池中,因为编译期间就可以确定结果
		
		System.out.println(s3 == s4);//true
		System.out.println(s3 == s5);//true
		System.out.println(s3 == s6);//true
	}
	
	@Test
	public void test04(){
     
		String s1 = "hello";
		String s2 = "world";
		String s3 = "helloworld";
		
		String s4 = s1 + "world";//s4字符串内容也helloworld,s1是变量,"world"常量,变量 + 常量的结果在堆中
		String s5 = s1 + s2;//s5字符串内容也helloworld,s1和s2都是变量,变量 + 变量的结果在堆中
		String s6 = "hello" + "world";//常量+ 常量 结果在常量池中,因为编译期间就可以确定结果
		
		System.out.println(s3 == s4);//false
		System.out.println(s3 == s5);//false
		System.out.println(s3 == s6);//true
	}

空字符串

(1)""
(2)new String()
(3)new String("")

@Test
	public void test07(){
     
		String s1; //局部变量未初始化
		String s2 = null;//初始化null
		String s3 = "";//空字符串常量对象
		String s4 = new String();//空字符串对象
		String s5 = new String("");//两个对象,一个是常量池中的,一个是堆中
		
      //System.out.println(s1);//无法使用
      //System.out.println(s2.length());//空指针异常
		
		System.out.println(s3.length());
		System.out.println(s4.length());
		System.out.println(s5.length());
	}

判断空字符串
四种方式:
(1)if(str != null && str.length() == 0)

(2)if(str != null && str.equals(""))
(3)if("".equals(str)) 推荐

(4)if(str!=null && str.isEmpty())

String对象的比较

(1)==:比较对象的地址
结论:只有两个字符串的常量对象比较时才会返回true,其他的都是false

(2)equals:比较字符串的内容,严格区分大小写
因为String类型重写了Object的equals

==与equals的详细分析和区别,请参考文章:equals与==的区别.

(3)equalsIgnoreCase(String anotherString) :比较字符串内容,不区分大小写

(4)大小比较,严格区分大小写
String类型实现了Comparable接口,重写了compareTo方法,严格区分大小写

@Test
	public void test06(){
     
		String s1 = new String("hello");
		String s2 = new String("helloworld");	
	/*	if(s1 > s2){//不能直接使用比较运算符		
		}*/
		
		if(s1.compareTo(s2) > 0){
     
			System.out.println(s1 + ">" + s2);
		}else if(s1.compareTo(s2) < 0){
     
			System.out.println(s1 + "<" + s2);
		}else{
     
			System.out.println(s1 + "=" + s2);
		}	
		//hello
	}

依次比较对应位置的字符
hello和Hello,先[0]位置的h和H,h>H,就直接认定hello>Hello
否则继续按位比较。

(5)大小比较:不区分大小写

@Test
	public void test07(){
     
		String s1 = new String("hello");
		String s2 = new String("Hello");
		
		if(s1.compareToIgnoreCase(s2) > 0){
     
			System.out.println(s1 + ">" + s2);
		}else if(s1.compareToIgnoreCase(s2) < 0){
     
			System.out.println(s1 + "<" + s2);
		}else{
     
			System.out.println(s1 + "=" + s2);
		}
		//hello=Hello
	}

String类常用方法

方法系列一

(1)int length():返回字符串的长度,返回的是字符的个数
因为String的内部(JDK1.9之前)用char[]实现,这个长度就是value数组的长度
(2)boolean isEmpty():是否是空字符串
(3)String toLowerCase()
String toUpperCase()

 @Test
    public void test1(){
     
        String str = "hello";
        System.out.println(str.toUpperCase());//HELLO
    }

(4)String trim() :去掉字符串的前后空白符

@Test
    public void test2(){
     
        String str = "    hello   world    ";
        str.trim();//上文讲过,String对象是不可变的,对String对象的操作都是产生一个新对象
        System.out.println("[" + str + "]");//[    hello   world    ]
        
        str = str.trim();//将str指向新产生的对象才能实现"改变"String对象的效果
        System.out.println("[" + str + "]");//[hello   world]
    }

(5)String concat():拼接,等价于+

@Test
	public void test3(){
     
		String s1 = "hello";
		String s2 = "world";
		String s3 = s1 + s2;
		String s4 = s1.concat(s2);
		
		System.out.println(s3 == s4);//false
		System.out.println(s3.equals(s4));//true
	}

方法系列二:和char相关

(1)char[] toCharArray() 转为char数组

@Test
	public void test01(){
     
		String str = "HelloWorld";
		
		//统计大写字母的个数
		char[] arr = str.toCharArray();
		int count = 0;
		for (int i = 0; i < arr.length; i++) {
     
			if(arr[i]>='A' && arr[i]<='Z'){
     
				count++;
			}
		}
		System.out.println("大写字母的个数:" +count);
	}

(2)char charAt(index) 获取某位置字符

(3)String(char[] arr)
(4)String(char[] arr,int offset, int count)

@Test
	public void test05(){
     
		char[] arr = {
     'h','e','l','l','o'};
		
		String string = new String(arr,2,3);//从[2]开始,取3个
		System.out.println(string);//llo
	}
	
	@Test
	public void test04(){
     
		char[] arr = {
     'h','e','l','l','o'};
		
		String string = new String(arr);
		System.out.println(string);//hello
	}

方法系列三:和byte相关

和编码与解码相关
编码:
把字符–>字节的过程,编给计算机用的

解码:
把字节–>字符的过程,解给人看的

编码:对于ASCII码范围内(0~127),无论用什么编码方式,结果都是一样的,一个字符对应一个字节的编码值

对于其他的字符,编码,结果不一定是几个字节,例如汉字:
UTF-8:变长的,但是大多数汉字都是3个字节
GBK、GB2312:固定2个字节
ISO8859-1:不支持中文,所有字符都变为1个字节

字符编码详细介绍:链接: https://blog.csdn.net/weixin_46369022/article/details/119091224.

(1)byte[] getBytes():
使用平台默认的字符编码进行编码

byte[] getBytes(编码方式):
(2)new String(字节数组)
new String(字节数组,编码方式)

@Test
	public void test02(){
     
		String str = "abc";
		byte[] bytes = str.getBytes();
		System.out.println(Arrays.toString(bytes));//[97, 98, 99]
	}

@Test
    public void test03() throws UnsupportedEncodingException {
     
        String str = "郭超";
        byte[] bytes = str.getBytes();
        System.out.println(Arrays.toString(bytes));//[-23, -125, -83, -24, -74, -123]

        String string = new String(bytes,"UTF-8");
        System.out.println(string);//郭超
    }

@Test
    public void test03() throws UnsupportedEncodingException {
     
        String str = "郭超";
        byte[] bytes = str.getBytes("GBK");
        System.out.println(Arrays.toString(bytes));//[-71, -7, -77, -84]

        String string = new String(bytes,"UTF-8");
        System.out.println(string);//乱码  ����
         //编码与解码字符集必须一致,否则会导致乱码
        String string2 = new String(bytes,"GBK");
        System.out.println(string2);//郭超

        String str3 = "郭超";
        byte[] bytes2 = str3.getBytes("ISO8859-1");        
        String string3 = new String(bytes2,"ISO8859-1");
        System.out.println(string3);//??   
                                    // 不符合中文编码,也无法解码
    }

方法系列四

(1)boolean startsWith(xx) 以xxx开头
(2)boolean endsWith(xx) 以xxx结尾

 @Test
    public void test3(){
     
        String fileName = "Hello.class";
        if(fileName.endsWith(".java")){
     
            System.out.println("Java的源文件");
        }else if(fileName.endsWith(".class")){
     
            System.out.println("字节码文件");
        }
       //字节码文件
        String str = "郭超真帅";
        System.out.println(str.startsWith("郭超"));//true
    }

方法系列五:和查找有关

(1)是否包含
boolean contanis
(2)int indexOf(xx):如果存在,返回下标,如果不存在返回-1
(3)int lastIndexOf(xx):如果存在,返回最后一个的下标,如果不存在返回-1

 @Test
    public void test03(){
     
        String fileName = "Hello.java.txt";
        //文件的后缀名是什么
        //截取文件的后缀名
        //(1)第一步,找到最后一个.的位置
        int index = fileName.lastIndexOf(".");
        System.out.println(index);//10
    }
    @Test
    public void test02(){
     
        String str = "123.45";
        int index = str.indexOf(".");
        System.out.println(index);//3
    }
    @Test
    public void test01(){
     
        String str = "123.45";
        if(str.contains(".")){
     
            System.out.println("是小数");
        }
    }

方法系列六:截取

(1)String substring(int beginIndex):从字符串的[beginIndex]截取到最后
(2)String substring(int beginIndex, int endIndex):截取字符串的[beginIndex,endIndex)部分

 @Test
    public void test04(){
     
        String str = "helloworldjava";
        String sub = str.substring(2, 6);
        System.out.println(sub);//llow
    }

    @Test
    public void test03(){
     
        String fileName = "Hello.java.txt";
        //文件的后缀名是什么
        //截取文件的后缀名
        //(1)第一步,找到最后一个.的位置
        int index = fileName.lastIndexOf(".");
        //(2)截取
        String sub = fileName.substring(index);
        System.out.println(sub);//.txt
    }

方法系列七:匹配原则(正则表达式)

boolean matches(正则表达式)

正则表达式:用于检测文本的格式
校验某个字符串是否符合xx规则
例如:
电话号码
甚至可以校验是否是移动号…
银行卡号
邮箱格式

  @Test
    public void test2(){
     
        String str = "12a345";
        //简单判断是否全部是数字,这个数字可以是1~n位

        //正则不是Java的语法,它是独立与Java的规则
        //在正则中\是表示转义,
        //同时在Java中\也是转义
        boolean flag = str.matches("\\d+");
        System.out.println(flag);//false
    }

    @Test
    public void test1(){
     
        String str = "123456789";

        //判断它是否全部由数字组成,并且第1位不能是0,长度为9位
        //第一位不能是0,那么数字[1-9]
        //接下来8位的数字,那么[0-9]{8}+
        boolean flag = str.matches("[1-9][0-9]{8}+");
        System.out.println(flag);//true
    }

方法系列八:替换

(1)String replace(target, value)
(2)String replaceAll(String regex, String replacement)
(3)String replaceFirst(String regex, String replacement) 替换第一次出现的
其中(2)和(3)支持正则表达式

  @Test
    public void test4(){
     
        String str = "hello244world.java;887";
        //把其中的非字母去掉
        str = str.replaceAll("[^a-zA-Z]", "");
        System.out.println(str);//helloworldjava

        String str2 = "中国共产党是执政党,中国共产党是领导党";
        str2 = str2.replaceAll("共产党", "***");
        System.out.println(str2);//中国***是执政党,中国***是领导党

        String str3 = "中国共产党是执政党,中国共产党是领导党";
        str3 = str3.replaceFirst("共产党", "***");
        System.out.println(str3);//中国***是执政党,中国共产党是领导党

        String str4 = "中国共产党是执政党,中国共产党是领导党";
        str4 = str4.replace("共产党", "***");
        System.out.println(str4);//中国***是执政党,中国***是领导党
    }

方法系列九:拆分

String[] split(xx)

 @Test
    public void test4(){
     
        String str = "张三.23|李四.24|王五.25";
        //|在正则中是有特殊意义,我这里要把它当做普通的|
        String[] all = str.split("\\|");

        //转成一个一个学生对象
        Student[] students = new Student[all.length];
        for (int i = 0; i < students.length; i++) {
     
            //.在正则中是特殊意义,我这里想要表示普通的.
            String[] strings = all[i].split("\\.");//张三,  23
            String name = strings[0];
            int age = Integer.parseInt(strings[1]);
            students[i] = new Student(name,age);
        }

        for (int i = 0; i < students.length; i++) {
     
            System.out.println(students[i]);
        }
        /*Student [name=张三, age=23]
        Student [name=李四, age=24]
        Student [name=王五, age=25]*/
    }

    @Test
    public void test3(){
     
        String str = "1Hello2World3java4atguigu5";
        str = str.replaceAll("^\\d|\\d$", "");
        String[] all = str.split("\\d");
        for (int i = 0; i < all.length; i++) {
     
            System.out.println(all[i]);
        }
        /*Hello
          World
          java
          atguigu*/

    }

    @Test
    public void test2(){
     
        String str = "1Hello2World3java4atguigu";
        str = str.replaceFirst("\\d", "");
        System.out.println(str);
        String[] all = str.split("\\d");
        for (int i = 0; i < all.length; i++) {
     
            System.out.println(all[i]);
        }

       /* Hello2World3java4atguigu
          Hello
          World
          java
          atguigu*/

    }


    @Test
    public void test1(){
     
        String str = "Hello World java atguigu";
        String[] all = str.split(" ");
        for (int i = 0; i < all.length; i++) {
     
            System.out.println(all[i]);
        }
    }
    /*Hello
     World
     java
     atguigu*/
}
class Student {
     
    private String name;
    private int age;

    public Student(String name, int age) {
     
        super();
        this.name = name;
        this.age = age;
    }
    public Student() {
     
        super();
    }

    @Override
    public String toString() {
     
        return "Student [name=" + name + ", age=" + age + "]";
    }
}

你可能感兴趣的:(javaSE,java)