Java基础复习05:正则表达式和常用API(包装类、String、StringBuilder、Object、System、Math、Arrays、Random、BigDecimal、时间日期类)

张开发
2026/6/20 12:25:51 15 分钟阅读
Java基础复习05:正则表达式和常用API(包装类、String、StringBuilder、Object、System、Math、Arrays、Random、BigDecimal、时间日期类)
Java常用API一、包装类1.1 基本介绍2.2 自动装箱/拆箱2.3 包装类的作用 字符串⇄基本数据类型2.4 总结二、String类2.1 String是不可变字符串2.2 String类创建对象的两种方式字符串常量池的位置方式1:使用 方式2:通过构造器new出来方式1/方式2的区别2.3 String s new(abc) 产生了两个对象2.4 发生编译优化的情况2.5 和equals2.6 常用API(遍历,截取,替换等)2.7 总结三、StringBuilder类3.1 基本介绍3.2 常用方法3.3 String类拼接字符串原理3.4 StringBuilder类拼接字符串原理3.5 使用案例3.6 总结四、Object类4.1 getClass得到运行类型4.2 Object类概述4.3 Object的toString方法4.4 Object的equals方法4.5 Objects的equals方法4.6 Objects的isNull方法4.7 总结五、工具类System5.1 概述5.2 常用方法六、工具类Math6.1 概述6.2 常用方法七、工具类Arrays7.1 常用方法7.2 Arrays类对于Comparator比较器的支持八、Random类8.1 基本使用8.2 减加法8.3 直接指定随机数区间九、BigDecimal类9.1 概述9.2 浮点数→BigDecimal对象 valueOf()9.3 常用API9.4 BigDecimal对象→浮点数 doubleValue()十、时间日期类10.1 Date类(了解即可)Date对象→时间毫秒值 getTime()时间毫秒值→Date对象 setTime()案例:计算1h121s后的时间为什么不推荐用旧的Date类10.2 SimpleDateFormat类(了解即可)作用(线程不安全)Date对象/时间毫秒值→String形式的时间 sdf.format()String形式的时间→Date对象 sdf.parse()案例:秒杀活动10.3 Calendar类(了解即可)如何得到Calendar对象常用方法10.4 JDK8新增日期类(重点掌握)概述LocalDate/LocalTime/LocalDateTime修改时间相关API-对时间运算DateTimeFormatter格式化日期时间/解析字符串时间Period计算日期间隔Duration计算时间间隔ChronoUnit计算时间间隔(最全面)Instant时间戳十一、ArrayList集合11.1 ArrayList概述11.2 ArrayList集合基本使用11.3 ArrayList对泛型的支持11.4 ArrayList常用API11.5 遍历并删除指定元素11.6 ArrayList存储自定义类型十二、正则表达式12.1 正则表达式案例12.2 匹配规则12.3 案例:匹配手机号/邮箱/电话12.4 通过正则表达式操作字符串一、包装类1.1 基本介绍Java认为一切皆对象 所以给八大基本类型也对应了他们的引用类型引用类型定义的变量才是对象2.2 自动装箱/拆箱基本类型的变量 和 对应的引用类型的变量可以互相转换2.3 包装类的作用 字符串⇄基本数据类型1.包装类的变量的值可以是null(引用类型才能是null) 容错率更高2.包装类可以把基本数据类型→字符串(用的少建议直接用拼接成字符串)既然是引用类型那一定是继承了Object 就有toString方法有下图三种方式3.字符串→真实数据类型(常用)注意:类型要对应(满足类型转换的规则) 才可以转比如int可以→double 反之不行parseXXX的返回值是基本数据类型推荐使用valueOf():就好像每个包装类都有同一个valueOf方法 上面每个parse都不一样注意valueOf()的返回值也是包装类交给基本类型也是发生了自动拆箱2.4 总结1.包装类实现了万物皆对象 有自动装箱和拆箱2.基本数据类型→字符串 建议直接 3.字符串→基本数据类型 建议用包装类.valueOf()二、String类2.1 String是不可变字符串java.lang.String类代表字符串String类定义的变量指向字符串对象可以调用API操作该字符串Java程序中所有的字符串文字比如abc 都是String类的对象(String name “yang”)String常被称为不可变字符串类型它的对象在创建之后不能被更改S1:以 方式给出的字符串对象 存储在堆内存中的字符串常量池S2:运算出来的字符串对象 在堆内存里 “创建出来的对象确实没有改变(传智 和 教育) 只是name存的地址指向的对象变了 所以说String的对象是不可变的对象S3:其实每次都在指向新的字符串对象之前” 创建出来的对象都没有改变2.2 String类创建对象的两种方式字符串常量池的位置JDK6及以前字符串常量池在方法区方法区的实现叫永久代JDK7做了一个重要改变:字符串常量池移到了堆(避免OOM)JDK8彻底删除永久代 方法区实现为Metaspace元空间 但不影响字符串常量池依然在堆中方式1:使用 name这个变量在栈内存存的是字符串对象的地址 这种方式创建的字符串JDK7开始存在堆内存中的字符串常量池方式2:通过构造器new出来有些不常用 IDEA会提醒其实是冗余的方式1/方式2的区别 :存储在堆内存的字符串常量池 内容相同则只存一份JVM会先检查字符串常量池 如果没有abc 就创建;如果有 就直接指向它new:即使内容相同每次new都是一个新的对象且存在堆内存中 而非字符串常量池true(注意比较的是s1和s2存储的地址 即判断是不是指向同一个对象):false(注意比较的是s1和s2存储的地址 即判断是不是指向同一个对象):2.3 String s new(“abc”) 产生了两个对象牢记: 在字符串常量池;new在堆内存new( “)根据传入的字符串内容(” 传入的内容 会在字符串常量池) 来创建一个字符串对象由于是比较 且s1 s2指向的不是同一个对象 所以结果是false2.4 发生编译优化的情况一般情况下运算符拼接出来的字符串 是放在堆内存 非常量池下图导致差异的核心在于:第一个的s3 必须在运行阶段才能确定右边s2c的值(编译的时候 s2是不确定的 运行起来s2才会指向常量池的ab) 从而确定s3的值 所以没有编译优化第二个的s2都是字面量 编译阶段就能确定右边的值就是abc所以发生编译优化如下图:源代码编译javac.exe→class文件 class文件再反编译 其实s2已经是abc了再用java.exe运行的时候s1 s2都是指向常量池的abc的如果不优化 s2的值要确定 首先要加载三个a b c对象 然后又把他们运算 再得到s2是abc但是很明显 s2是可以确定的(因为编译的时候 a b c全都是确定的固定的字面量) 做这个优化 以提高性能2.5 和equals永远比较的是变量存储的值是否相等只不过值分为数值类型和引用类型数值类型:比较基本数据类型的数值是否相等引用类型:比较地址值是否相等 即是不是指向同一个对象所以如果需要比较内容是否相等 数值类型可以用 ; 字符串(引用类型)适合用equals(String类已经重写了equals)sc输入的字符串不是 的形式 所以在堆内存equals只关心字符串内容是否相等2.6 常用API(遍历,截取,替换等)replace是返回一个替换后新的字符串 原来的字符串不会被改变包括toCharArray,substring等API 都没有真正改变原来的字符串2.7 总结1.一般情况运算出来的字符串对象在堆内存(除非右边都是字面量在 会发生编译优化)2.new出来的字符串对象在堆内存而且即使内容一样 也不是同一个对象3.sc输入的字符串对象 存放在堆内存的(不是纯 出来的字符串对象 都是在堆内存里)4. 创建的字符串对象 在堆内存中的字符串常量池 且是不可变的相同内容的字符串只会在常量池中存储一份5.进行运算的时候 每个值都是固定的字面量 就会有编译优化三、StringBuilder类3.1 基本介绍String:不可变字符串StringBuilder:可变字符串3.2 常用方法无论是拼接还是翻转 他们的返回值其实都是this(也就是当前对象)拼接append()拼接完之后 又把原对象返回了 所以支持链式编程;sout(sb1)不是地址而是内容说明SB这个类 本身也重写了toString()方法;这里重写toString作用1看到字符串内容 作用2把SB类型的字符串恢复成String类型反转reverse()反转之后返回的仍然是当前对象this返回对象内容长度length()恢复成String类型toString()Java认为字符串还是String类型的(习惯用String接一个字符串)SB只是操作字符串的手段 最终目的还是希望得到String所以操作完SB对象 需要把它恢复成String类型(否则不能直接传给String类型做参数)3.3 String类拼接字符串原理String是不可变字符串 每次拼接都会指向新对象原来的对象会被当成垃圾回收 不断指向新对象 不断垃圾回收 浪费性能下图执行到s2那里做运算的时候:S1.a是直接用引号创建的 在常量池 ;“b同理 也在常量池S2.然后new一个SB对象 把a,b拼接到SB对象里;S3.再调用toString()方法 把该SB对象→String字符串对象;S4.再让s2指向那个最新的String类的字符串对象ab”每次运算 堆内存中就生成一个SB对象和一个同样内容的String对象 然后变量再指向String对象 所以非常浪费性能3.4 StringBuilder类拼接字符串原理只产生一个StringBuilder类的对象 不产生多余对象所以字符串拼接/反转建议使用StringBuilderString拼接字符串用运算每次都产生一个SB对象和一个String对象并且会一直发生垃圾回收 性能差SB拼接调用API 可以链式编程 而且只产生一个对象在一个对象容器中完成各种操作3.5 使用案例处理字符串用StringBuilder返回的结果恢复成String3.6 总结1.String拼接字符串是用做的 每次都会产生两个对象(除非编译优化) 一个是StringBuilder的 一个是String的2.StringBuilder拼接字符串调用append() 只会产生一个SB对象3.一般用String类定义字符串 用StringBuilder类更高效地操作字符串最终还是要调用toString()恢复成String类四、Object类4.1 getClass得到运行类型得到当前对象的运行类型4.2 Object类概述主要学习Object类中常用的两个方法:toString方法和equals方法以及Object类的一个子类:工具类Objects类的静态方法equals()4.3 Object的toString方法如果想看到的是对象的内容信息 而不是地址 就需要重写toString()默认情况 子类对象调用toString就是去调用Object类的toString 返回的是当前对象的地址Object类的toString主要是为了给子类重写 然后打印相应的对象内容信息sout(s) 就算不写toString 默认s也会去调用toString子类重写toString方法重写toString了 那就调用子类重写的sout(s)默认去调用toString 找到的也是子类重写的4.4 Object的equals方法默认是调用Object类的equals 会比较两个对象的地址是否相同 即比较是不是同一个对象如果不重写equals效果其实跟是一样的数值类型用:就是比较数值 比较的是内容引用类型用:也是比较数值 比较的是存的地址是否是同一个子类重写equals()可以根据自己的需求来定制比较规则s1.equals(s2):s1是方法调用者(所以this就代表s1) ; s2是传进来的参数传递给了o(也是多态的写法)注意到o的编译类型是Object 点能点出什么取决于Object 而Object没有name属性name是s2特有的为了访问到子类特有的 需要向下转型(也就是强转 需要instanceOf先判断一下)IDEA也可以直接生成官方重写的代码 如下图注意到比较字符串的时候没有直接用 字符串对象1.equals(字符串对象2) 而是调用了Objects类的equals方法(下图第二个if那里 this.getClass()的this可以省略)注释2、那里写的不够好 应该是判断o(参数)和this(方法调用者)是不是同一个(运行)类型4.5 Objects的equals方法Object类是一切类的父类 包括Objectspublic final class Objects extends Objectjava.util.Objects只是一个JDK7开始提供的工具类 它没有重写Object类的equals()public static boolean equals(Object a, Object b)Objects.equals()是一个静态方法 它会安全地调用对象自己的equals() 避免空指针字符串比较内容用equalsString的equals也是被重写过的(比较的是字符串内容)但是s1.equals(s2) 可能会出现空指针异常:使用Objects效果一样 但是更加安全:查看equals()源码 源码很简洁 但是实际上考虑的很周全 包括都是null的情况只有a不是null的时候 才可能去调用a.equals(b) 不会出现null指针异常先判断引用是否相同再安全调用a对象所在类自己重写的equals()理解调用流程下面Objects.equals(s1,s2) 其实最终还是调用了s1.equals(s2)不过加了s1s2 s1是不是null的安全校验s1如果是null 直接s1.equals(s2)会报错s1如果是null Objects.equals(s1,s2) 会正确输出结果4.6 Objects的isNull方法public static boolean isNull(Object obj) 判断变量是否为null本质套了个方法壳子4.7 总结1.Object类的equals()默认比较地址(是否是同一个对象) 作用和一样2.String类的equals方法是比较字符串内容的说明String的equals方法也是被重写过的3.Object类的toString()默认返回全限名地址 返回值是String 一般重写让他返回对象的内容4.比较数值类型的时候 比较的就是值;比较引用类型的时候 比较的是地址;本质上比较的都是变量存的值是否相同5.sout(XXX对象名) 默认调用toString()打印对象全限名地址 如果不是 就说明这个对象的类重写过toString方法5.以后比较对象的内容的步骤:先重写equals()方法 再调用Objects.equals(对象1,对象2)进行比较五、工具类System5.1 概述它是工具类 提供静态方法 是不能实例化出对象的5.2 常用方法正常终止参数就给0终止Java虚拟机 了解即可 不要使用JVM终止 之后的代码再也不会执行到了获取当前时间毫秒值数组拷贝六、工具类Math6.1 概述工具类不需要创建对象 而是直接调用静态方法实现的功能6.2 常用方法之前用的Random是一个类这个random是Math类其中一个静态方法取绝对值向上/下取整求指数次方四舍五入round的返回类型是long 所以一定是四舍五入成整数随机数范围[0.0 , 1.0)七、工具类Arrays7.1 常用方法Arrays类是一个数组操作工具类(都是静态方法)public static String toString(数组):数组内容public static void sort(数组):默认升序public static int binarySearch(数组,目标值):二分查找 前提是数组必须有序7.2 Arrays类对于Comparator比较器的支持Arrays的sort()对于有值特性的数组默认是升序排序(下图的规则就是升序的规则)如果要降序排序怎么办?如果排序的元素是对象怎么办?如果想要降序:注意如果用比较器的方式 那么被排序的数组必须是引用类型的元素(包装类或者自定义类型等)对于对象数组的自定义排序:注意重写的那个compare方法要求返回值是int(作为比较的信号位)为什么不重写Student的toString() sout(Arrays.toString(学生数组))打印的就是地址而不是内容?核心原因在于:Arrays.toString()会调用数组里的每个元素的toString()来拼接字符串(如果元素对应的类没有重写toString 就调用Object默认的)八、Random类8.1 基本使用一般都是左闭右开8.2 减加法如果是需要3-10的随机数也就是0-7 3也就是nextInt(8)38.3 直接指定随机数区间Random的父类有一个方法 可以指定一个区间[10,30]九、BigDecimal类9.1 概述为了解决浮点数底层运算的精度问题可以先把浮点数先封装成一个BigDecimal对象(调用静态方法valueOf)然后调用BigDecimal提供的方法进行运算最后再把运算结果(也是BigDecimal类型的)恢复成浮点数类型(通过doubleValue方法)9.2 浮点数→BigDecimal对象 valueOf()如果要用构造器的方式 建议用参数是String的那个构造器 如new new BigDecimal(“1.0”)最建议用静态方法valueOf(double val)9.3 常用API再调用API进行运算 解决了精度问题最后再把运算结果恢复成浮点数除法里有一个重载方法 可以用于解决1.0/3.0除不尽就报错的情况加 减 乘 除c1是引用类型 存的是地址 sout(c1)打印的不是地址 而是对象内容说明BigDecimal也重写了toString()注意事项:BigDecimal一定要精度运算 如果除不尽就报错需要调用另一个divide方法进行四舍五入(下图保留2位小数进行四舍五入)RoundingMode(舍入模式)其实是一个枚举类9.4 BigDecimal对象→浮点数 doubleValue()调用BigDecimal提供的doubleValue()把运算结果恢复回浮点类型十、时间日期类10.1 Date类(了解即可)Date对象→时间毫秒值 getTime()Date类的对象在Java代表的是当前所在系统的此刻日期时间sout(Date的对象) 发现不是地址 而是一个具体时间说明也是重写了toString方法的那么获取时间毫秒值就有两种方式了 Date类的getTime(); System类currentTimeMillis()时间毫秒值→Date对象 setTime()时间毫秒值一般用于运算比较多 有下图两种转换方式(setTime方法或者构造器)案例:计算1h121s后的时间得到1h121s后的时间毫秒值 再→Date对象为什么不推荐用旧的Date类java.util.Date设计有严重缺陷 又难用又容易出 bug 所以JDK8推出了全新的时间日期API(LocalDateTime等)官方明确不推荐再用旧的Date1.Date月份从0开始 容易写错2.Date对象可变 线程不安全3.SimpleDateFormat线程不安全 多线程会出错4.API混乱 很多方法已废弃5.JDK8后有更好用的LocalDate/LocalDateTime10.2 SimpleDateFormat类(了解即可)作用(线程不安全)1.把Date对象 或 时间毫秒值→格式化成需要的时间形式2.把字符串的时间形式→解析成Date对象3.注意SimpleDateFormat线程不安全 用新的DateTimeFormatterDate对象/时间毫秒值→String形式的时间 sdf.format()一般用第二个有参构造器 指定格式化的形式获得一个用于格式化的对象 并指定格式化的形式是什么然后可以格式化Date对象 或 时间毫秒值String形式的时间→Date对象 sdf.parse()字符串时间→时间毫秒值:sdf.parse(字符串时间)→Date对象 再getTime()→时间毫秒值时间毫秒值→字符串时间:sdf.format(时间毫秒值)→字符串时间案例:秒杀活动如果得到了Date对象 不知道after和before方法也可以把Date用getTime()→时间毫秒值来比较10.3 Calendar类(了解即可)如何得到Calendar对象Calendar类获取信息更加灵活 他可以单独拿出年月日等时间字段因为他是抽象类 所以getInstance得到的肯定不是Calendar类本身的对象 而是他的子类对象(多态的写法)常用方法注意:Calendar的对象是可变日期对象一旦修改后 其对象本身表示的时间将产生变化cal.get(filed) 有哪些filed(都是static final修饰的常量) 直接打印cal对象就可以看到了cal.set(filed,value) 修改某个时间字段cal.add()也会修改cal对象 下面cai.getTime拿到的已经是修改之后的时间的Date对象了Calendar的对象是可变日期对象一般就是拿到信息查看 而不会修改信息10.4 JDK8新增日期类(重点掌握)概述几乎都是不可变类型LocalDate/LocalTime/LocalDateTime他们三个获取到对象有两种方式(都是静态方法).now() 或者 .of(传入一个时间)LocalDate年月日(获取和当天有关的信息)LocalTime时分秒(获取更精确的时间信息)也是有now和of两个方式获取LocalTime对象LocalDateTime前两者之合 信息更全面 兼容前面所有API所以这个时间对象可以转换成前前两个时间对象修改时间相关API-对时间运算LocalDate/LocalTime/LocalDateTime是不可变对象修改时间之后 会返回一个新的时间对象MonthDay对象记录日月信息 可以用.of指定日月信息 也可以.from从LocalDate对象直接拿到DateTimeFormatter格式化日期时间/解析字符串时间DateTimeFormatter是线程安全的而SimpleDateFormat线程不安全调用format之后返回的格式化时间的类型是String类型的LocalDateTime→String的时间:format()String的时间→LocalDateTime:LocalDateTime.parse()Period计算日期间隔针对日期(年月日 LocalDate)下图打印的结果的意思是:已经出生24年2个月17天Duration计算时间间隔可以针对到时分秒(LocalDateTime)ChronoUnit计算时间间隔(最全面)它相当于一个工具类Instant时间戳知道Instant时间戳也能表示时间即可十一、ArrayList集合11.1 ArrayList概述ArrayList是集合中的一种 它支持索引数组:存储东南西北 周几集合:购物车存储11.2 ArrayList集合基本使用add()的返回值是TF 添加成功就返回T 实际上 ArrayList调用add添加元素肯定会返回T的下图两个add其实构成方法重载11.3 ArrayList对泛型的支持ArrayList是支持泛型的(不是所有类都支持泛型的 要看看源码里有没有E)ArrayListE:它其实就是一个泛型类 可以在编译阶段就约束集合对象只能操作某种数据类型JDK1.7开始 右边的类型声明可以省略虽然ArrayList支持存储任意类型的数据 但为了规范 建议约定好某个ArrayList对象所能存放的数据的类型如果就是要操作任意类型 那泛型也建议写成Object类11.4 ArrayList常用APIremove(指定索引) 返回被删除的元素remove(指定元素) 返回删除是否成功 如果有重复 默认删除的是第一次出现的元素set(索引处,新元素)返回的是索引处旧元素的值11.5 遍历并删除指定元素注意用move删除每次删除之后 对象真的会发生改变比如[98, 77, 66, 89, 79, 50, 100] 删掉77 就是[98, 66, 89, 79, 50, 100]如果此时索引一直是1 那就从指向77变成指向66了方法1:每次remove之后立即对i-- 防止i跳过了元素而导致bugimportjava.util.ArrayList;publicclasstest001{publicstaticvoidmain(String[]args){ArrayListIntegerscoresnewArrayList();scores.add(98);scores.add(77);scores.add(66);scores.add(89);scores.add(79);scores.add(50);scores.add(100);System.out.println(scores);//[98, 77, 66, 89, 79, 50, 100]for(inti0;iscores.size();i){if(scores.get(i)80){scores.remove(i);//只要发生删除的操作 就-- 否则会跳过元素 导致漏删i--;}}System.out.println(scores);}}方法2:从后往前遍历 可以直接避免跳过元素importjava.util.ArrayList;publicclasstest001{publicstaticvoidmain(String[]args){ArrayListIntegerscoresnewArrayList();scores.add(98);scores.add(77);scores.add(66);scores.add(89);scores.add(79);scores.add(50);scores.add(100);System.out.println(scores);//[98, 77, 66, 89, 79, 50, 100]for(intiscores.size()-1;i0;i--){if(scores.get(i)80){scores.remove(i);}}System.out.println(scores);}}11.6 ArrayList存储自定义类型用集合存储自己定义的类实例化出来的一些对象存储的是对象的地址 而不是对象本身下图list2是匿名对象的写法内存图:十二、正则表达式12.1 正则表达式案例需求如下传统方式:正则表达式:12.2 匹配规则matches是String类提供的API左边两个是指定匹配规则 并且默认只匹配一个字符贪婪的两次中的X就表示一个匹配规则 X{n,} 就表示X这个匹配规则至少出现n次这么多规则 如果忘记了可以在API文档搜索pattern12.3 案例:匹配手机号/邮箱/电话完成如下三个需求:手机号:邮箱:用户名是数字 字母 下划线 1-30位然后是后面的域名 只有数字字母 不包括下划线 2-20位然后是. 应该写成\. 否则单独一个.代表的就是任意字符 需要用\转义 而\又需要\转义()括起来的表示域名是字母数字 2-20位 {1,2}表示最多有两级域名(小括号里那一坨出现1次或2次)电话号码:前面的区号是3-7位(以0开头) 中间的-可有可无 后面的号码是5-20位-?表示:-出现1次或者0次 也就是可有可无爬取需要的信息(拓展 了解):regex只是我们自己定义的一个匹配规则 无法被Java识别需要再通过compile方法得到一个匹配规则对象(字符串→匹配规则对象)12.4 通过正则表达式操作字符串下图是String类提供的方法

更多文章