Java常用类

String

string是一个引用类型,本身也是一个class,内部是一个char[]数组表示

String s1 = "Hello";
String s2 = new String(new char[]{'h','e','l','l','o'});
//这两种方法都是可行的

Java字符串不可变,一旦String对象被创建,它的值就不可变。

任何看似修改字符串的操作都是在创建新的String对象。

这是通过内部private final char[]字段,以及没有任何修改char[]的方法实现的。

字符串比较

比较字符串内容是否相同,必须使用equals()方法而不能用==

// String
public class Main {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
    }
}

在这里,两个字符串比较都为true。

实际是因为字符串常量池的优化机制,字面量赋值会使用字符串常量池,使用new创建对象就可以得到 ,为false,equals为true,原因是,比较的是内存地址,而equals()才是比较内容

忽略大小写比较,使用equalsIgnoreCase()方法

String类还提供多种方法搜索子串、提取子串。

//是否包含子串
"Hello".contains("ll");//true

注意:contains()方法的参数是CharSequence而不是String,因为CharSequence是String实现的一个接口。

这样的目的是为了使用更高级的抽象层次,可以使得contains()方法更加灵活,可以处理多种文本来源,避免不必要的类型转换。

搜索字符串的例子

"Hello".indexof("l");//查找字符在字符串的中出现的第一个位置  2
"Hello".lastIndexOf("l");//查找字符在字符串的中出现的最后一个位置 3
"Hello".startsWith("He");//判断字符串是否以子串开头 true
"Hello".endsWith("lo");//判断字符串是否以子串结尾 true

提取子串的例子

"Hello".subString(2);//"llo"截取从第二位开始后的所有字段
"Hello".substring(2,4);//"ll"截取从第二位到第四位(不包括第四位)的所有字段

去除首尾空白字符

使用trim()方法可以移除字符串首尾空白字符。

空白字符包括:空格、\t、\r、\n.

  • trim()方法并不会改变字符串内容,而是返回一个新的字符串

strip()方法也可以移除字符串首尾空白字符,区别在于strip()方法会将类似中文空格字符\u3000也移除

字符串还提供isEmpty()和isBlank()方法判断字符串是否为空和空白字符串

"".isEmpty(); // true,因为字符串长度为0
"  ".isEmpty(); // false,因为字符串长度不为0
"  \n".isBlank(); // true,因为只包含空白字符
" Hello ".isBlank(); // false,因为包含非空白字符

替换子串

替换子串有两种方法。

  • 根据字符或字符串替换
String s = "hello";
s.replace('l', 'w'); // "hewwo",所有字符'l'被替换为'w'
s.replace("ll", "~~"); // "he~~o",所有子串"ll"被替换为"~~"
  • 通过正则表达式替换
String s = "A,,B;C ,D";
s.replaceAll("[\\,\\;\\s]+", ","); // "A,B,C,D"

分割字符串

分割字符串使用split()方法,传入的参数只能是正则表达式。

String s = "A,B,C,D";
String[] ss = s.split("\\,"); // {"A", "B", "C", "D"}

拼接字符串

join()方法,可以用指定的字符连接字符串数组

String[] arr = {"A","B","C"};
String s = String.join("***",arr);

concat()方法(X,不推荐)

String s1 = "hello";
String s2 = "world";
String result = s1.concat(" ").concat(s2);

格式化字符串

formatted()和format()方法,可以传入其他参数,替换占位符,生成新的字符串

// String
public class Main {
    public static void main(String[] args) {
        String s = "Hi %s, your score is %d!";
        System.out.println(s.formatted("Alice", 80));
        System.out.println(String.format("Hi %s, your score is %.2f!", "Bob", 59.5));
    }
}

有几个占位符就需要传入几个参数。参数类型要和占位符一致。

常用占位符:

%s :显示字符串;

%d: 显示整数;

%x:显示十六进制整数

%f:显示浮点数

如果不确定用啥就用%s,因为%s可以显示任何数据类型。

类型转换

  1. 将任意基本类型或引用类型转换为字符串,可以使用静态方法valueOf().
String.valueOf(123); // "123"
String.valueOf(45.67); // "45.67"
String.valueOf(true); // "true"
String.valueOf(new Object()); // 类似java.lang.Object@636be97c
  1. 要把字符串类型转换为其他类型,就需要根据情况
  • 字符串->int类型
int n1 = Integer.parseInt("123"); // 123
int n2 = Integer.parseInt("ff", 16); // 按十六进制转换,255
  • 字符串->boolean类型
boolean b1 = Boolean.parseBoolean("true"); // true
boolean b2 = Boolean.parseBoolean("FALSE"); // false

Integer有个getInteger(String)方法,它不是将字符串转换为int型,而是将该字符串对应的系统变量转换为Integer。

Integer.parseInt(String s) Integer.getInteger(String s)
字符串 -> 整数转换 获取系统属性 ->整数转换
返回int基本数据类型 返回Integer包装类对象,如果属性不存在或不是数字则返回null
异常:如果字符串不是有效整数,抛出NumberFormatException 不会抛出异常,如果属性不存在或格式错误,则返回null
  • 字符串 -> char[]

String和char[]类型可以互相转换

char[] cs = "hello".toCharArray();
String s = new String(cs);

StringBuilder

对于String类型,我们可以直接用+拼接字符串。但是这样每次都是创建新的字符串,会浪费内存还会影响GC效率。

为了高效拼接字符串,Java提供了StringBulider,这是一个可变对象,可以预分配缓冲区,所以在StringBulider中新增字符,不会创建新的临时对象。

支持链式操作的类,定义的方法需要返回this。

StringJoiner

用分隔符拼接数组的需求很常见,Java提供StringJoiner来完成这事

var sj = new StringJoiner(", ", "hello ","!")
    //第一个参数为分隔符。
    //第二个参数为开头
    //第三个参数为结尾

String提供静态方法join(),这个方法内部使用StringJoiner来拼接字符串,

在不需要指定开头结尾的时候,用String.join()更方便。

包装类型

将基本类型视为对象(引用类型)。可以直接使用,不需要自己定义。

包装类型都是不变类,一旦创建Integer对象,该对象不变

// Integer:
public class Main {
    public static void main(String[] args) {
        int i = 100;
        // 通过new操作符创建Integer实例(不推荐使用,会有编译警告):
        Integer n1 = new Integer(i);
        // 通过静态方法valueOf(int)创建Integer实例:
        Integer n2 = Integer.valueOf(i);
        // 通过静态方法valueOf(String)创建Integer实例:
        Integer n3 = Integer.valueOf("100");
        System.out.println(n3.intValue());
    }
}

因为int和Integer可以互相转换,Java编译器可以自动在int和Integer之间转型

Integer n = 100; // 编译器自动使用Integer.valueOf(int)
int x = n; // 编译器自动使用Integer.intValue()

这种直接把int变为Integer的赋值写法,称为自动装箱(Auto Boxing),反过来,把Integer变为int的赋值写法,称为自动拆箱(Auto Unboxing)。

意义:

1.用于泛型。泛型只支持引用类型,不支持基本系统

2.允许null值

3.包装类型提供很多静态方法和实例方法

4.用于发射和API设计

JavaBean

符合以下规范的class被称为JavaBean

  • 若干private实例字段
  • 通过public方法来读写实例字段

JavaBean主要用于传递数据

枚举JavaBean属性

使用Java核心库提供的Introspector

枚举类

Java中,我们可以通过static final定义常量,

使用常量值表示一组枚举值时,编译器无法检查其合理性

关键字enum

enum Weekday{
    SUN,MON,TUE,WED,THU,FRI,SAT;
}

enum定义枚举类,只需依次列出枚举的常量名。

好处:

1.编译器会自动检查类型错误

2.不可能引用到非枚举的值

3.不同类型的枚举不能互相比较或赋值

**enum的比较 **

使用enum定义的枚举类是一种引用类型。引用类型比较,需要使用equals()方法,但是enum类型可以例外。

因为enum类每个常量在JVM中只有一个唯一实例,所以可以直接用==比较

特点:

  • 只能定义出enum的实例,而无法通过new操作符创建实例
  • 定义的每个实例都是引用类型的唯一实例
  • enum类型无法被继承
  • 可以将enum类型用于switch语句

enum类方法

name(),返回常量名

String s = Weekday.SUN.name(); //"SUN"

ordinal(),返回定义的常量的顺序,从0开始

int n = Weekday.FRI.ordinal(); //5

将Weekday枚举常量如果要和int转换,使用ordinal()方法不推荐,因为修改顺序,编译器检查不出这种错误。

可以通过定义private构造方法,并且给每个枚举常量添加字段

enum Weekday {
    MON(1), TUE(2), WED(3), THU(4), FRI(5), SAT(6), SUN(0);

    public final int dayValue;

    private Weekday(int dayValue) {
        this.dayValue = dayValue;
    }
}

注意:

判断枚举常量的名字,始终使用name()方法,千万不要调用toString()。

因为toString()可以被重写,而name()不行

记录表

不变类具有以下特点:

  • 定义class时用final,无法派生子类;
  • 每个字段使用final,保证创建实例后无法修改任何字段。

record

record Point(int x, int y) {}
相当于
final class Point extends Record {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int x() {
        return this.x;
    }

    public int y() {
        return this.y;
    }

    public String toString() {
        return String.format("Point[x=%s, y=%s]", x, y);
    }

    public boolean equals(Object o) {
        ...
    }
    public int hashCode() {
        ...
    }
}
  • 使用record关键字,可以一行写出一个不变类
  • 编译器会默认安装record声明的变量顺序自动创建构造方法,并在方法中赋值。

如果我们要对参数进行检查,我们可以添加检查逻辑

  • 可以定义静态方法

record类只用于保存数据

声明record,编译器会自动生成:

  • 私有final字段,对应组件列表中每个组件
  • 规范构造函数,包含所有组件的构造函数
  • 公共访问器方法,方法名就是组件名本身
  • equals() 和 hashCode()方法,基于所有组件完成
  • toString()方法,返回一个包含记录类名和所有组件名及值的字符串

BigInteger

Java中,CPU提供整型最大范围是64位long型整数

如果使用的整数范围超过了long该怎么办?通过软件模拟一个大整数

java.math.BigInteger就是用来表示任意大小的整数,BigInteger内部用一个int[]数组来模拟一个非常大的整数,BigInteger不会有范围限制,缺点就是速度比较慢

对BigInteger做运算的时候,只能使用实例方法。

BigInteger i1 = new BigInteger("1234567890");
BigInteger i2 = new BigInteger("12345678901234567890");
BigInteger sum = i1.add(i2); // 12345678902469135780

同时可以将BigInteger转换为long型。

BigInteger i = new BigInteger("123456789000");
System.out.println(i.longValue()); // 123456789000
System.out.println(i.multiply(i).longValueExact()); // java.lang.ArithmeticException: BigInteger out of long range
.longValue() .multiply().longValueExact()
功能 静默截断,返回BigInteger低64位,无论是否在long范围内 精确计算后验证,先计算后验证是否在long范围内
安全性 不安全,如果值超出long范围,会返回一个错误/无意义的值,但不会通知 安全,如果超出范围,会抛出异常
异常 从不抛出异常 可能抛出ArithmeticException

BigInteger和Integer、Long一样,属于不变类,并且也继承Number类

所以也可以通过类型转换方法(byteValue()、……)

如果需要准确地转换位基本类型,可以使用(intValueExact()、……)

BigDecimal

和BigInteger类似,BigDecimal可以表示一个任意大小、精度完全准确的浮点数。

BigDecimal用scale()表示小数位数,可以通过stripTrailingZeros()方法,去掉小数后面的0

BigDecimal d1 = new BigDecimal("123.45");
BigDecimal d2 = new BigDecimal("123.4500");
BigDecimal d3 = new BigDecimal("1234500");
System.out.println(d1.scale()); // 2,两位小数
System.out.println(d2.scale()); // 4
System.out.println(d3.scale()); // 0
BigDecimal d4 = d3.stripTrailingZeros();
System.out.println(d4.scale());//-2

如果一个BigDecimalscale()返回负数,例如,-2,表示这个数是个整数,并且末尾有2个0。

.setScale()方法,可以传入参数,精度和截断方法(四舍五入 or 直接截断)

比较两个BigDecimal,既要求两个数相等,还要求scale()相等,

所以一般不使用equals()方法进行比较,

总是使用compareTo()比较两个BigDecimal()的值

BigDecimal其实是由一个BigInteger和一个scale表示的。

BigDecimal同样从Number继承,也是不可变对象。

常用工具类

Math

  • Math.abs(x),求x的绝对值
  • Math.max(),Math.min(),求最大值、最小值
  • Math.pow(x,y),计算xy
  • Math.sqrt(x),计算 x1/2
  • Math.exp(x),计算ex
  • Math.log(x),计算以e为底的对数
  • Math.log10(x),计算以10为底的对数
  • 三角函数
  • 数学常量,Math.PI、Math.E
  • Math.random(),生成随机数x

HexFormat

HexFormat可以将byte[]数组和十六位进制字符串转换。

byte[]数组转换为十六进制字符串,可以使用formatHex()方法

import java.util.HexFormat;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        byte[] data = "Hello".getBytes();
        HexFormat hf = HexFormat.of();
        String hexData = hf.formatHex(data); // 48656c6c6f
    }
}

从十六进制字符串转换为byte[]数组,可以使用parseHex()方法。

byte[] bs = HexFormat.of().parseHex("48656c6c6f");

Random

Random用来创建伪随机数,指定种子,随机数序列是完全一致

安全随机数采用SecureRandom()方法生成。

它使用RNG(Random Number Generator)算法