java全端课--常用类

67 阅读8分钟

一、数学计算相关

1.1 Math类

java.lang包

  • double Math.PI:圆周率
  • double Math.random():返回[0,1 ) 范围的小数
  • double Math.sqrt(参数x):返回x的平方根
  • 基本数据类型 Math.abs(参数x):返回x的绝对值,这个方法有重载形式,支持多种参数类型。
  • double Math.ceil(x):对x向上取整
  • double Math.floor(x):对x向下取整
  • double Math.round(x):类似于四舍五入(值先+0.5再向下取整
  • double Math.pow(x, y):求x的y次方,x,y可以是整数可以是小数
  • double Math.max(x,y):求x,y的最大值
  • double Math.min(x,y):求x,y的最小值

1.2 BigInteger和BigDecimal类

java.math包

  • BigInteger:用于表示任意大小的整数,它不受int,long这个范围的限制。
  • BigDecimal:用于表示任意精度的小数,它不受float,double这个范围和精度的限制。

问:int,Integer,BigInteger的区别?

(1)int是基本数据类型,Integer,BigInteger是引用数据类型

(2)Integer是int的包装类,可以与int之间进行自动装箱和自动拆箱,可以互相自由转换。

int和BigInteger不能自由转换,需要通过方法来完成转换。

(3)当int和Integer表示不了的数字范围可以用BigInteger。

(4)int支持丰富的运算符。Integer,BigInteger要完成计算,需要调用方法。

package com.mytest.math;

import org.junit.Test;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;

public class TestBig {
    @Test
    public void test1(){
//        long a = 863214563214563214589321456325632521452L;//超出long范围
        BigInteger a = new BigInteger("863214563214563214589321456325632521452");
        BigInteger b = new BigInteger("896954562145215245244253215323296214586214521452");

        //凡是对象要完成xx功能,就是通过调用方法
        System.out.println("和:" + a.add(b));
        System.out.println("差:" + a.subtract(b));
        System.out.println("乘积:" + a.multiply(b));
        System.out.println("商:" + a.divide(b));
        System.out.println("余数:" + a.remainder(b));
    }

    @Test
    public void test2(){
        BigDecimal a = new BigDecimal("896954562145215245244253215323296214586214521452.0");
        BigDecimal b = new BigDecimal("86214522.395251");
        //凡是对象要完成xx功能,就是通过调用方法
        System.out.println("和:" + a.add(b));
        System.out.println("差:" + a.subtract(b));
        System.out.println("乘积:" + a.multiply(b));
        //System.out.println("商:" + a.divide(b));//除不尽
        System.out.println("商:" + a.divide(b,1000, RoundingMode.CEILING));
        //这里的1000代表保留到小数点后1000位
        //这里的RoundingMode.CEILING代表第1001位的怎么处理,CEILING代表进位
        System.out.println("余数:" + a.remainder(b));

    }
}

1.3 产生随机数

  • double Math.random()
  • java.util.Random 类有很多nextXxx的方法,用于产生各种类型的随机数值。

[a,b)范围的整数

package com.mytest.math;

import org.junit.Test;

import java.util.Random;

public class TestRandom {
    @Test
    public void test1(){
        double d = Math.random();//[0,1)
        //[a,b)范围的整数:[10,50)
        int a = 10;
        int b = 50;
        int num = (int) (Math.random() * (b - a) + a);
        System.out.println("num = " + num);
    }

    @Test
    public void test2(){
        Random r = new Random();
        double a = r.nextDouble();
        boolean b = r.nextBoolean();
        int c = r.nextInt();//int范围的任意整数
        int d = r.nextInt(100);//[0,100)
        int e = r.nextInt(10,50);//[10,50)  这个方法的版本比较新

        System.out.println("a = " + a);// 0.9671156811567097
        System.out.println("b = " + b);//true
        System.out.println("c = " + c);//-327530929
        System.out.println("d = " + d);//52
        System.out.println("e = " + e);//48
    }
}

二、日期时间类

在Java中日期时间API大的改动,主要经历了3代。

2.1 第1代

第1代:java.util.Date

缺点:

  • 不支持不同时区的日期时间,也不友好,因为无法根据不同地区的用户习惯显示日期时间值。
  • 线程安全问题
  • 日期对象可变性
  • 第1代:格式化工具类SimpleDateFormat

2.2 第2代

java.util.Calendar(日历类):解决了时区的问题
java.util.TimeZone:时区
java.util.Locale:地区和语言环境

缺点:

  • 很难用
  • 不支持SimpleDateFormat
  • 日期时间对象可变
  • 线程安全问题

2.3 第3代

JDK8引入了第3代的日期时间API。主要集中在java.time及其子包中,挑选一部分讲一下。

解决了对象不可变的问题,使用方便性的问题。第3代也是线程安全的。

2.3.1 本地的日期时间类(重要)

  • LocalDate:本地日期
  • LocalTime:本地时间
  • LocalDateTime:本地日期时间
//今天的日期
LocalDate today = LocalDate.now();
//现在时间
LocalTime now = LocalTime.now();
//现在日期+时间
LocalDateTime dateTime = LocalDateTime.now();

2.3.2 日期或时间间隔

  • Period:日期间隔
  • Duration:时间间隔
LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(1990,8,16);
Period p = Period.between(birthday, today );
System.out.println(p);//P34Y3M28D 34年 3个月 28天

LocalTime now = LocalTime.now();
LocalTime end =LocalTime.of(12,0,0);
Duration d = Duration.between(now, end);
System.out.println(d);//PT28M50.8431153S

2.3.3 其他时区的日期时间

  • ZonedDateTime:不同时区的日期时间
  • ZoneID:时区
ZoneId id = ZoneId.of("America/Los_Angeles");
ZonedDateTime time = ZonedDateTime.now(id);
System.out.println(time);
//2024-12-13T19:33:07.531241200-08:00[America/Los_Angeles]

2.3.4 格式化

  • DateTimeFormatter:代替第1代SimpleDateFormat,对第3代日期时间对象进行格式化。
LocalDateTime now = LocalDateTime.now();

//2024年12月14日 10时54分10秒
//DateTimeFormatter与SimpleDateFormat
//自定义模板
DateTimeFormatter  dt = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
String str = dt.format(now);
System.out.println(str);
//2024年12月14日 11时36分00秒

三、数组工具类(重要)

3.1 Arrays工具类

Arrays工具类提供了各种静态方法,来为各种类型的一维数组服务。

3.2 System.arraycopy方法

  • 可以生成新数组
  • 可以对原数组进行操作(删除原数组中的某个元素、添加新元素)
package com.mytest.array;

import org.junit.Test;

import java.util.Arrays;

public class TestSystemArraycopy {
    @Test
    public void test1(){
        int[] nums = {1,2,3,4,5};
        int[] arr = new int[10];

        //想要实现将nums的5个元素,复制到arr数组中 arr[0]~arr[4]
        System.arraycopy(nums, 0, arr, 0, 5);
        /*
        从原数组复制元素到目标数组
        第1个参数:原数组
        第2个参数:要复制的元素的最左边的下标
        第3个参数:目标数组
        第4个参数:目标数组要存储新元素最左边的下标
        第5个参数:一共几个元素
         */
        System.out.println(Arrays.toString(arr));
    }
}

四、字符串(重要)

4.1 字符串拼接工具类(了解)

StringJoiner工具类用于拼接字符串。

//拼接 hello,world,java这些单词为一个字符串,拼接时想要指定前缀,后缀,中间的连接符
StringJoiner joiner  =new StringJoiner("-","[","]");
joiner.add("hello");
joiner.add("world");
joiner.add("java");
String str = joiner.toString();
System.out.println(str);//[hello-world-java]

4.2 可变字符序列/字符串缓冲区

StringBuffer和StringBuilder。

它们的内部有一个数组,用于存储一组字符,随着字符数量的增加,内部数组会自动扩容。默认数组的长度是16(默认扩容规则是:数组的长度 * 2 + 2)。

    • append
    • insert
    • delete(start, end)
    • deleteCharAt(下标)
    • replace
    • setCharAt
    • setLength (1.改短:其余后续字符丢弃,2.改长:补空字符)
    • reverse
    • length
    • indexOf (查找字符出现的位置下标)
    • lastIndexOf (查找字符最后出现的位置下标)

StringBuffer和StringBuilder的区别?

StringBuffer:古老的,线程安全的,效率较低。

StringBuilder:较新的,线程不安全,效率较高。单线程情况下,优先使用它。

4.3 不可变字符序列

String类的方法:

4.3.1 系列1:基础方法

  • .toUpperCase() :转大写
  • .toLowerCase() :转小写
  • .trim() :去掉前后空白符
  • .isEmpty() :判断是否没有任何字符,即 ""
  • .isBlank() :没有有效字符,只有空字符(空格,\t,\n 等)
  • .equals() : 比较字符串的内容
  • .equalsIgnoreCase() :忽略大小写比较(它是String类自己扩展的,不是Object类)
  • .compareTo() :比较大小(String类实现了Comparable接口)
  • .compareToIgnoreCase() :忽略大小写比较大小(此方法是String类自己扩展的,不是Comparable接口)

4.3.2 系列2:与char[]和byte[]有关

String str = "hello";
//可以转为char[]
char[] array = str.toCharArray();
System.out.println(Arrays.toString(array));
//[h, e, l, l, o]

//---------------------------------------------

char[] arr = {'a','b','c','d'};
//把char[]转为字符串
String str = new String(arr);
String str2 = String.valueOf(arr);
System.out.println(str);//abcd
System.out.println(str2);//abcd

String的对象,在JVM内存中是以Unicode字符集,UTF-16和Latin1(ISO8859-1)的编码方式。

  • String的对象只有 ASCII码表范围的字符,就使用Latin1(ISO8859-1)的编码方式
  • String的对象包含其他字符,例如汉字,就使用UTF-16的编码方式。

4.3.3 系列3:其他方法

String str = "hello.java";

  • str.startsWith("hello");//true
  • str.endsWith(".java");//true
  • str.indexOf("o");//4
  • str.lastIndexOf("a");//9
  • str.contains("a");//true
  • str.substring(star, end);
  • str.replace("o","a"); //"hella.java" //所有替换
  • str.replaceFirst("o","a"); //替换一次
  • str.replaceAll("o","a"); //所有替换
  • str.matches("[a-zA-Z]+");

4.4 String类的原理(面试重灾区)

4.4.1 String类的特点

问:String类能不能被继承?

String不能被继承,因为它是final

问:String类的对象可变吗?

不可变

问:String类的对象如何做到不可变的?

String的内部使用value数组来存储一组字符,JDK9之前是char[],JDK9之后byte[],它们都有final修饰。意味着这个数组不能修改地址,即不能扩容(因为扩容会创建新数组)。

这个数组是private,意味着在String类的外部不能直接操作这个value数组,需要通过String提供的各种方法来使用和修改这个value数组。在String类中所有涉及到修改value数组元素的方法,都是返回新的String对象。

问:String底层是如何存储一串字符的?

JDK9之前是char[],JDK9之后byte[]。

问:为什么要从char[]换为byte[]数组?

1个byte占1个字节,1个char占2个字节。

那么程序中大部分字符串都是英文字母组成的,这些字母其实用1个字节就可以存储了,从char改为byte可以节省一半内存。

问:对于汉字等,怎么办呢?

String会自由选择,如果字符串中都是ASCII码表范围的字符,那么1个字符用1个字节,coder是0,采用Latin1编码方式。

如果字符串中包含ASCII码表以外的字符,例如汉字,那么每一个字符都用2个字节,coder是1,采用UTF16编码方式。

问:字符串对象为什么要设计为不可变?

因为字符串对象不可变,才能被共享。

    @Test
    public void test2(){
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1 == s2);//true
        //因为这里"hello"被共享了,它是字符串常量,s1和s2使用同一个"hello"对象
    }

问:哪些字符串对象可以被共享呢?

  • 直接""引起来的对象
  • 字符串对象.intern()的结果

问:String s1 = new String("hello");有几个字符串对象

答:2个

问:两种拼接用那种 +concat

答:先用 + (能合并就合并了,可以共享)