java2_day01常用类之String类

Java常用类之String类

目录

  1. 字符串String相关的类

  2. JDK8之前的日期时间API

  3. JDK8中新日期时间API

  4. java比较器

  5. System类

  6. Math类

  7. BigInteger与BigDecimal

1 String

  • String类:代表字符串。Java程序中的所有字符串字面值(如“abc")都作为此类的实例实现。

  • String是一个final类,代表不可见的字符序列。

  • 字符串是常量,用双引号引起来表示。他们的值在创建之后不能更改。

  • String对象的字符内容是存储在一个字符数组value[]中的。

1.1 String的特性

  • image-20220404105832646

 package com.xue.java;
 
 import jdk.jfr.StackTrace;
 import org.junit.Test;
 
 /**
  * String的使用
  * @author xinxueqi
  * @create 2022.04.04
  */
 
 public class StringTest {
     /*
     String:字符串,使用""表示
     1. String声明位final,不可被继承
     2. String实现了Serializable接口:表示字符串是支持序列化的。
              实现了comparable接口:表示String可以比较大小
     3. String内部定义了final char[]   value用于存储字符串数据
     4. String:代表不可变的字符序列。简称:不可变性
         体现:1. 当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
               2. 当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
               3. 当调用String的replace()方法修改指定字符或者字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
     5. 通过字面量的方式(区别于new方式),给一个字符串赋值,此时的字符串值声明在字符串常量池中
     6. 字符串常量池中是不会存储相同内容的字符串的
     */
     @Test    //右键引入Test,单元测试(不用因为一个小功能就写一个main方法)
     public void test1(){
         String s1 = "abc";    //字面量的定义方式,是个类,但是不用new,
         String s2 = "abc";
         s1 = "hello";
         System.out.println(s1);   //输出hello
         System.out.println(s2);   //abc
         System.out.println("=================================");
         String s3 = "abc";
         s3 += "def";
         System.out.println(s3);     //abcdef
         System.out.println("=================================");
         String s4 = "abc";
         String s5 = s4.replace('a','m');
         System.out.println(s4);    //abc
         System.out.println(s5);    //mbc
 
    }
 }

1.2 String对象的创建

 String str = "hello";
 
 //本质上this.value = new char[0];
 String s1 = new String();
 
 //this.value = original.value;
 String s2 = new String(String original);
 
 //this.value = Arrays.copyOf(value, value.length);
 String s3 = new String(char[] a);
 
 String s4 = new String(char[] a, int startIndex, int count);  //从几开始放几个
  • 两种不同的实例化方式:

     /*
     String的实例化方式:
     方式一:通过字面量定义的方式
     方式二:通过new+构造器的方式
 
     面试题:String s = new String("abc");方式创建对象,在内存中创建了几个对象?
           两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc"
      */
     @Test
     public void test2(){
 
         //通过字面量定义的方式:此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。
         String s1 = "javaEE";
         String s2 = "javaEE";
 
         //通过new+构造器的方式:此时的s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。
         String s3 = new String("javaEE");
         String s4 = new String("javaEE");
         System.out.println(s1 == s2);   //true
         System.out.println(s1 == s3);   //false
         System.out.println(s1 == s4);   //false
         System.out.println(s3 == s4);   //false
 
         System.out.println("========================");
         Person p1 = new Person("Tom", 12);
         Person p2 = new Person("Tom", 12);
 
         System.out.println(p1.name.equals(p2.name));   //true
         System.out.println(p1.name == p2.name);   //true
 
         p1.name = "Jerry";
         System.out.println(p2.name);    //Tom
    }

结果如下:

image-20220404155451316

image-20220404155518768

image-20220404162606692

  • 字符串的拼接特性

 /*
 结论:
 1. 常量与常量的拼接结果在 常量池中。且常量池中不会存在相同内容的常量。
 2. 只要其中有一个是变量,结果就在堆中。
 3. 如果拼接的结果调用intern()方法,返回值就在常量池中。
  */
 
 @Test
     public void test4(){
         String s1 = "javaEEhadoop";
         String s2 = "javaEE";
         String s3 = s2 + "hadoop";
         System.out.println(s1 == s3);//false
 
         final String s4 = "javaEE";  //final定义后,s4是常量
         String s5 = s4 + "hadoop";
         System.out.println(s1 == s5);  //true
    }
 
 
 @Test
 public void test3(){
     String s1 = "javaEE";
     String s2 = "hadoop";
 
     String s3 = "javaEEhadoop";  //字面量
     String s4 = "javaEE"+"hadoop";  //两个字面量的链接
     String s5 = s1+"hadoop";  //有变量,都不在常量池了
     String s6 = "javaEE"+s2;
     String s7 = s1 + s2;
     System.out.println(s3 == s4);    //true
     System.out.println(s3 == s5);    //false
     System.out.println(s3 == s6);    //false
     System.out.println(s3 == s7);    //false
     System.out.println(s5 == s6);    //false
     System.out.println(s5 == s7);    //false
     System.out.println(s6 == s7);    //false
 
     String s8 = s5.intern();   //返回值得到的s8使用的常量值是常量池中已经存在的
     System.out.println(s3 == s8);
 }

image-20220404192133665

1.3 一道面试题

  • 考察字符串的不可变性(涉及到值传递的问题)

 package com.xue.exer;
 /**
  * 一道面试题
  * User: xinxueqi
  * Date: 2022/4/4
  * Time: 19:33
  * Description:
  */
 public class StringTest {
     String str = new String("good");
     char[] ch = {'t', 'e', 's', 't'};
     public void change(String str, char ch[]){
         str = "test ok";
         ch[0] = 'b';
         System.out.println(str);   //test ok
    }
 
     public static void main(String[] args) {
         StringTest ex = new StringTest();
         ex.change(ex.str, ex.ch);
         System.out.println(ex.str);   //good,字符串不可变性
         System.out.println(ex.ch);    //best
    }
 }

1.4 扩展(JVM内存分析)

image-20220404195635964

  • JDK8及以上:字符串常量池在方法区里。

1.5 String常用方法1

  • int length(): 返回字符串的长度 return value.length

  • char charAT(int index): 返回某索引处的字符return value[index]

  • boolean isEmpty(): 判断是否是空字符串 return value.length == 0

  • String toLowerCase(): 使用默认语言环境,将String中的所有字符转换为小写

  • String toUpperCase(): 使用默认语言环境,将String中的所有字符转换为大写

  • String trim(): 返回字符串的副本,忽略前导空白和尾部空白

  • boolean equals(Object obj):比较字符串的内容是否相同

  • boolean equalsIgnoreCase(String anotherString): 与equals方法类似,忽略大小写

  • String contact(String str): 将指定字符串连接到此字符串的结尾。等价于用“+”

  • int compare To(String anotherString): 比较两个字符串的大小

  • String substring(int beginIndex): 返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。

  • String substring(int beginIndex, int endIndex): 返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。

  • 测试程序如下:

 package com.xue.java;
 
 import org.junit.Test;
 
 /**
  * Created with IntelliJ IDEA.
  * User: xinxueqi
  * Date: 2022/4/4
  * Time: 20:15
  * Description:
  */
 public class StringMethodTest {
     @Test
     public void test2(){
         String s1 = "HelloWorld";
         String s2 = "helloworld";
         System.out.println(s1.equals(s2)); //false
         System.out.println(s1.equalsIgnoreCase(s2)); //true,忽略大小写
 
         String s3 = "abc";
         String s4 = s3.concat("def");
         System.out.println(s4);  //abcdef
 
         String s5 = "abc";
         String s6 = new String("abe");
         System.out.println(s5.compareTo(s6));   //-2,转换成ascii码进行比较了,设计到字符串排序
 
         String s7 = "北京尚硅谷education";
         String s8 = s7.substring(2);
         String s9 = s7.substring(2, 8);
         System.out.println(s7);  //北京尚硅谷education
         System.out.println(s8);  //尚硅谷education
         System.out.println(s9);  //尚硅谷edu,不包含第8个字符
    }
 
 
     @Test
     public void test1(){
         String s1 = "HelloWorld";
         System.out.println(s1.length()); //10
         System.out.println(s1.charAt(5));//从0开始。输出位w
         System.out.println(s1.isEmpty());//false
 
         String s2 = s1.toLowerCase();
         System.out.println(s1); //s1是不变的
         System.out.println(s2); //helloworld
 
         String s3 = " he llo   world   ";
         String s4 = s3.trim();
         System.out.println("-----"+ s3 + "-----");  //----- he llo   world   -----
         System.out.println("-----"+ s4 + "-----");  //-----he llo   world-----,去除前后空格
 
 
    }
 
 }

1.6 String常用方法2

  • boolean endsWith(String suffix): 测试此字符串是否以指定的后缀结束

  • boolean startsWith(String prefix): 测试此字符串是否以指定的后缀开始

  • boolean startsWith(String prefix, int toffset): 测试此字符串从指定索引开始的子字符串是否以指定前缀开始。

  • 测试程序如下:

     package com.xue.java;
     
     import org.junit.Test;
     
     /**
      * Created with IntelliJ IDEA.
      * User: xinxueqi
      * Date: 2022/4/4
      * Time: 21:14
      * Description:
      */
     public class StringMethodTest2 {
         @Test
         public void test1(){
             String str1 = "helloworld";
             boolean b1 = str1.endsWith("ld");
             System.out.println(b1); //true
     
             boolean b2 = str1.startsWith("He");
             System.out.println(b2); //false
     
             boolean b3 = str1.startsWith("ll", 2);
             System.out.println(b3);//true
     
        }
     }
  • boolean contains(CharSequence s): 当且仅当此字符串包含指定的char值序列时,返回true

  • int indexOf(String str): 返回指定子字符串在此字符串中第一次出现处的索引

  • int indexOf(String str, int fromIndex): 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始

  • int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引

  • int lastIndexOf(String str, int fromIndex): 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索

注:indexOf和lastIndexOf方法如果未找到都是返回-1

  • 测试程序如下:

 @Test
 public void test2(){
     String str1 = "helloworld";
     String str2 = "wo";
     System.out.println(str1.contains(str2)); //true,大小写严格要求
 
     System.out.println(str1.indexOf("lo"));  //3,首次出现的位置
     System.out.println(str1.indexOf("lo", 5));  //-1,从5之后开始查找
 
     String str3 = "hellorworld";
     System.out.println(str3.lastIndexOf("or")); //7,从后往前找,但是索引号还是从前开始的
     System.out.println(str3.lastIndexOf("or",6));//4,从第六个开始,从后往前
     //什么情况下,insdexOf(str)和lastIndexOf(str)返回值相同?
     //情况1:存在唯一的一个str
     //情况2:不存在
 
 }

1.7 String常用方法3

  • String replace(char oldChar, char newChar): 返回一个新的字符串,它是通过用newChar替换此字符串中出现的所有oldChar得到的

  • String replace(CharSequence target, CharSequence replacement): 使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串

  • String replaceAll(String regex, String replacement): 使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串

  • String replaceFirst(String regex, String replacement): 使用给定的replacement替换此字符串匹配给定的正则表达式的第一个子字符串

 

  • boolean matches(String regex): 告知此字符串是否匹配给定的正则表达式

  • String[] split(String regex): 根据给定正则表达式的匹配拆分此字符串

  • String[] split(String regex, int limit): 根据匹配给定的正则表达式的拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中

 package com.xue.java;
 
 import org.junit.Test;
 
 /**
  * Created with IntelliJ IDEA.
  * User: xinxueqi
  * Date: 2022/4/4
  * Time: 22:08
  * Description:
  */
 public class StringMethodTest3 {
 
 
     @Test
     public void test1(){
         String str1 = "北京尚硅谷教育北京";
         String str2 = str1.replace('北', '东');
         System.out.println(str1); //北京尚硅谷教育北京
         System.out.println(str2); //东京尚硅谷教育东京
 
         String str3 = str1.replace("北京", "上海");
         System.out.println(str3); //上海尚硅谷教育上海
 
         System.out.println("=================");
         String str = "12hello34world5java7891mysql1456";
         //把字符串中的数字替换成, ,如果结果中开头和结尾有,的话去掉
         String string = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
         //其中\\d+代表的是正则表达式,数字的意思;后边^代表开头,|代表加上,$代表结尾;
         System.out.println(string);
 
         System.out.println("=================");
         str = "12345";
         //判断str字符串中是否全部由数字组成,即有1-n个数字组成
         boolean matches = str.matches("\\d+");
         System.out.println(matches);
         String tel = "0571-4534289";
         //判断这是否是一个杭州的固定电话
         boolean result = tel.matches("0571-\\d{7,8}"); //7位或者8位
         System.out.println(result);
 
         System.out.println("=================");
         str = "hello|world|java";
         String[] strs = str.split("\\|");   //以|进行切割
         for (int i = 0; i < strs.length; i++) {
             System.out.println(strs[i]);
        }
         System.out.println();
         str2 = "hello.world.java";
         String[] strs2 = str2.split("\\."); //以.进行切割
         for (int i = 0; i < strs2.length; i++) {
             System.out.println(strs2[i]);
        }
 
    }
 }

1.8 String与其他类型转换

1.8.1 String与基本数据类型转换

  • 只要有变量参与了,就会存在堆里

 package com.xue.java;
 
 import org.junit.Test;
 
 /**
  * Created with IntelliJ IDEA.
  * User: xinxueqi
  * Date: 2022/4/5
  * Time: 9:30
  * Description:涉及到String类与其他结构之间的转换
  */
 public class StringTest1 {
     /*
     String与基本数据类型、包装类之间的转换
     String-->基本数据类型、包装类: 调用包装类的惊天方法:parsexxx(str)
     基本数据类型、包装类-->String: 调用String重载的valueof(xxx)
      */
     @Test
     public void test1(){
         String str1 = "123";
         //int num = (int)str1; //错误的,子父类才能进行强转
         int num = Integer.parseInt(str1);
         System.out.println(num);   //123
        String str2 = String.valueOf(num);
         System.out.println(str2);  //"123",是个字符串了,但是其实输出的还是123
         String str3 = num + "";  //在堆里,因为有变量参与了
         System.out.println(str1 == str3); //false,一个在堆里,一个在常量池
    }
 
 }

1.8.2 String与char[]之间的转换

 /*
 String与char[]型数组之间的转换
 String -->char[] : 调用String的toCharArray()
 char[] -->String : 调用String的构造器
  */
 @Test
 public void test2(){
     String str1 = "abc123";
     char[] charArray = str1.toCharArray();
     for (int i = 0; i < charArray.length; i++) {
         System.out.println(charArray[i]);//a b c 1 2 3
    }
     char[] arr = new char[]{'h', 'e', 'l', 'l', 'o'};
     String str2 = new String(arr);
     System.out.println(str2);
 
 }

1.8.3 String与byte()字节数组之间的转换

 /*
 String与byte[]字节数组之间的转换
 编码:String -->byte[]: 调用String的getBytes()
 解码:byte[]-->String: 调用String的构造器
 编码:字符串-->字节
 解码:字节-->字符串
  */
 @Test
 public void test3(){
     String str1 = "abc123";
     byte[] bytes = str1.getBytes();//使用默认的字符集进行转换
     System.out.println(Arrays.toString(bytes)); //97, 98, 99, 49, 50, 51
     System.out.println("=====================");
     String str2 = new String(bytes); //使用默认字符集进行解码,注意编码字符集与解码要对应,否则会出现乱码
     System.out.println(str2);  //abc123
 }

2 StringBuffer与StringBuilder类

  • 三者区别和创建时底层源码分析

 package com.xue.java;
 
 import org.junit.Test;
 
 /**
  * Created with IntelliJ IDEA.
  * User: xinxueqi
  * Date: 2022/4/5
  * Time: 10:43
  * Description:关于StringBuffer和StringBuilder的使用
  */
 public class StringBufferBuilderTest {
     /*
     String、StringBuffer、StringBuilder三者的异同?
     String: 不可变的字符序列;底层使用char[]存储;
     StringBuffer:可变的字符序列; 线程安全的,效率偏低; 底层使用char[]存储;
     StringBuilder:可变的字符序列; jdk5.0新增,线程不安全,效率高; 底层使用char[]存储;
     源码分析:
     String str = new String(); //底层做的new char[0];
     String str1 = new String("abc"); //底层做的new char[]{'a','b','c'};
 
     StringBuffer sb1 = new StringBuffer(); //new char[16];相当于底层创建了一个长度是16的数组
     sb1.append('a'); //value[0] = 'a';
     sb1.append('b'); //value[1] = 'b'; //可以在线增加,所以是可变
 
     StringBuffer sb2 = new StringBuffer("abc"); // char[] value = new char["abc".length()+16];
 
     问题1. System.out.println(sb2.length());   //长度还是看数组的内容,只是空间有16个长度
     问题2. 扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组
            默认情况下,扩容为原来容量的2倍加2,同时将原有数组中的元素复制到新数组中来。
 
     指导建议:开发中建议大家使用:StringBuffer(int capacity) 或者 StringBuilder(int capacity),
              避免之后复制之后才能扩容,影响运行效率
      */
     @Test
     public void test1(){
         StringBuffer sb1 = new StringBuffer("abc");
         sb1.setCharAt(0, 'm');
         System.out.println(sb1);   //直接把sb1改变了
 
         System.out.println(sb1.length());
    }
 }

2.1 StringBuffer类的常用方法

  • StringBuffer append(xxx): 提供了许多的append()方法,用于进行字符串拼接

  • StringBuffer delete(int start, int end): 删除指定位置的内容

  • StringBuffer replace(int start, int end, String str): 把[start,end]位置替换为str

  • StringBuffer insert(int offsset, xxx): 在指定位置插入xxx

  • StringBuffer reverse(): 把当前字符序列逆转

 

  • public int indexOf(String str) //返回str首次出现的位置

  • public String substring(int start, int end) //返回一个从start开始到end索引结束的左闭右开区间的子字符串。

  • public int length()

  • public char charAt(int n) //返回索引处的字符

  • public void setCharAt(int n, char ch) //将指定位置改成新的ch

     @Test
     public void test2(){
         StringBuffer s1 = new StringBuffer("abc");
         s1.append(1); //可数字
         s1.append('2'); //可字符
         System.out.println(s1);  //abc12
 
         //s1.delete(2,4); //ab2,删除
         //System.out.println(s1); //都是左闭右开
 
         //s1.replace(2,4,"hello"); //abhello2,替换
         //s1.insert(2,"false"); //abfalsec12,插入
         //s1.reverse(); //21cba
         String s2 = s1.substring(1,3);  //截取
         System.out.println(s1);
         System.out.println(s2);
    }

总结:

  • 增:append(xxx)

  • 删:delete(int start, int end)

  • 改:setCharAt(int n, char ch), replace(int start, int end, String str)

  • 查:charAt(int n)

  • 插:insert(int offsset, xxx)

  • 长度:length()

  • 遍历:for + charAt()

2.2 StringBuffer、StringBuilder与String效率问题

 @Test
 public void test3(){
     //初始设置
     long startTime = 0L;
     long endTime = 0L;
     String text = "";
     StringBuffer buffer = new StringBuffer("");
     StringBuilder builder = new StringBuilder("");
     //开始对比
     startTime = System.currentTimeMillis();
     for (int i = 0; i < 20000; i++) {
         buffer.append(String.valueOf(i));
    }
     endTime = System.currentTimeMillis();
     System.out.println("StringBuffer的执行时间:"+ (endTime - startTime));//5
 
     startTime = System.currentTimeMillis();
     for (int i = 0; i < 20000; i++) {
         builder.append(String.valueOf(i));
    }
     endTime = System.currentTimeMillis();
     System.out.println("StringBuilder的执行时间:"+ (endTime - startTime)); //2
 
     startTime = System.currentTimeMillis();
     for (int i = 0; i < 20000; i++) {
         text = text +i;
    }
     endTime = System.currentTimeMillis();
     System.out.println("String的执行时间:"+ (endTime - startTime));  //235
 }

结论:效率从高到低 StringBuffer >StringBuilder> String

 

知识补充

1 IDEA创建JAVA Class时自动生成头部文档注释

  • File->settings->Editor->File and Code Templates->Class

  • 原来模板

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end
#parse("File Header.java")
public class ${NAME} {
}
  • 修改后模板

#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME};#end

/**
\* Created with IntelliJ IDEA.
\* User: ${USER}
\* Date: ${DATE}
\* Time: ${TIME}
\* To change this template use File | Settings | File Templates.
\* Description:
\*/
public class ${NAME} {
}

 

 

posted @   诺不克  阅读(77)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示