<Java>12 常用类

本文最后更新于:2023年6月27日 上午

12 常用类

12.1 包装类

包装类(Wrapper):针对 八种基本数据类型 相应的 引用类型

有了类的特点,就可以调用类中的方法

基本数据类型 包装类 父类
boolean Boolean Object
char Character Object
int Integer Number
float Float Number
double Double Number
long Long Number
short Short Number
byte Byte Number
void Void Object

12.1.1 装箱和拆箱

  • 手动装箱和拆箱(JDK 5 以前)

    int n1 = 100;
    Integer integer = new Integer(n1);			// 手动装箱
    Integer integer2 = Integer.valueOf(n1);		// 手动装箱
    int i = integer.intValue();					// 手动拆箱
  • 自动装箱和拆箱(JDK 5 以后)

    n2 = 200;
    Integer integer3 = n2;						// 自动装箱
    int j = integer3;							// 自动拆箱

    虽然可以自动装箱、拆箱,但使用 == 直接比较两个包装类时,仍然是比较其地址。以下比较通常会失败:

    Integer ia = 1000;
    Integer ib = 1000;
    System.out.print(ia == ib);					// false

    但,Java 实现仍有可能使其成立。Byte、Boolean 以及 Short、Integer 中 [-128, 127] 间的值已被包装到固定的对象中。对他们的比较可以成功。

    Integer ia = 127;
    Integer ib = 127;
    System.out.print(ia == ib);					// true

    由此可见,使用 == 直接比较两个包装类会带来不确定性。尽量使用 equals 方法对包装类进行比较。

装箱与拆箱是 编译器 的工作。在生成可执行的字节码文件时,编译器已经插入了必要的方法调用。

12.1.2 包装类和 String 的相互转换

  • 包装类转 String

    >Integer integer = 100;
    >String str1 = integer + "";					//方法1(自动拆箱)
    >String str2 = integer.toString();			//方法2(toString方法)
    >String str3 = String.valueOf(integer);		//方法3(自动拆箱)
  • String 转包装类:

    String str4 = "100";
    Integer integer2 = Integer.parseInt(str4);	//方法1(自动装箱)
    Integer integer3 = new Integer(str4);		//方法2(构造器)

12.1.3 包装类的常用方法

  • Integer.MIN_VALUE:返回最大值

  • Double.MAX_VALUE:返回最小值

  • byteValue()doubleValue()floatValue()intValue()longValue()

    按各种基本数据类型返回该对象的值

  • Character.isDigit(int):判断是不是数字

    Character.isLetter(int):判断是不是字母

    Character.isUpperCase(int):判断是不是大写字母

    Character.isLowerCase(int):判断是不是小写字母

    Characher.isWhitespace(int):判断是不是空格

  • Character.toUpperCase(int):转成大写字母

    Character.toLowerCase(int):转成小写字母

  • Integer.parseInt(string):将 String 内容转为 int

    Double.parseDouble(string)

  • Integer.toBinaryString(int):将数字转为 2 进制表示的字符串

    Integer.toHexString(int):将数字转为 16 进制表示的字符串

    Integer.toOctalString(int):将数字转为 8 进制表示的字符串

    特别地,浮点数类型的包装类只有转成 16 进制的方法。而 Short、Byte 及其他包装类无此方法

  • int Integer.bitCount(i int):统计指定数字的二进制格式中 1 的数量

12.1.4 strictfp 关键字

由于不同处理器对于浮点数寄存采取不同策略(有些处理器使用 64 位寄存 double,有些则是 80 位),对于浮点数的运算在不同平台上可能出现不同结果。

使用 strictfp 关键字标记的方法或类中,所有指令都会使用严格统一的浮点数运算。

比如,把 main 方法标记为 strictfp

public static strictfp void main(String[] args) {
    double ᓚᘏᗢ = 1 / 13.97;
    System.out.println(ᓚᘏᗢ);
}

12.2 String

  1. String 对象用于保存字符串,也就是一组字符序列

  2. 字符串常量对象是用双引号扩起的字符序列。例如 "你好"

  3. 字符串的字符使用 Unicode 字符编码。一个字符(不论字母汉字)占 2 字节

  4. 常用构造器:

    • String str1 = new String();

    • String str2 = new String(String original);

    • String str3 = new String(char[] a);

    • String str4 = new String(char[] a, int startIndex, int count);

      这句意思是:char[]startIndex 起的 count 个字符

  5. String 实现了接口 SerializableComparable ,可以 串行化和 比较大小

    串行化:即,可以被网络传输,也能保存到文件

  6. Stringfinal 类,不能被继承

  7. String 有属性 private final char[] value; 用于存放字符串内容。

    valuefinal 属性。其在栈中的地址不能修改,但堆中的内容可以修改。

12.2.1 String 构造方法

  • 直接指定

    String str1 = "哈哈哈";

    该方法:先从常量池看是否有 "哈哈哈" 数据空间。有的场合,指向那个空间;否则重新创建然后指向。

    这个方法,str1 指向 常量池中的地址。

  • 构造器

    String str2 = new String("嘿嘿嘿");

    该方法:先在堆中创建空间,里面维护一个 value 属性,指向 或 创建后指向 常量池的 "嘿嘿嘿" 空间。

    这个方法,str2 指向 堆中的地址

12.2.2 字符串的特性

  • 常量相加,看的是池

    String str1 = "aa" + "bb";				//常量相加,看的是池

    上例由于构造器自身优化,相当于 String str1 = "aabb";

  • 变量相加,是在堆中

    String a = "aa";
    String b = "bb";
    String str2 = a + b;					//变量相加,是在堆中

    上例的底层是如下代码

    StringBuilder sb = new StringBuilder();
    sb.append(a);
    sb.append(b);
    str2 = sb.toString();	//sb.toString():return new String(value, 0, count);

12.2.3 String 的常用方法

以下方法不需死记硬背,手熟自然牢记

  • boolean equals(String s):区分大小写,判断内容是否相等

    boolean equalsIgnoreCase(String s):判断内容是否相等(忽略大小写)

  • boolean empty():返回是否为空

  • int charAt(int index):获取某索引处的字符(代码单元)。

    必须用 char c = str.charAt(15);,不能用 char c = str[15];

    int codePointAt(int index)

    int length():获取字符(代码单元)的个数

    —— 代码单元,见 [2.6.2.4 字符本质与编码表]

    IntStream codePoints():返回字符串中全部码点构成的流

    long codePoints().count():返回真正长度(码点数量)

    —— 流,见 [27.4 Stream API]

  • int indexOf(String str):获取字符(串)在字符串中第一次出现的索引。如果找不到,返回 -1

    int indexOf(int char) 参数也可以传入一个 int。由于自动类型转换的存在,也能填入 char

    int indexOf(String str, int index):从 index 处(包含)开始查找指定字符(串)

    int lastIndexOf(String str):获取字符在字符串中最后一次出现的索引。如果找不到,返回 -1

  • String substring(int start, int end):返回截取指定范围 [start, end) 的 字符串

    String substring(int index):截取 index(包含)之后的部分

  • String trim():返回去前后空格的新字符串

  • String toUperCase():返回字母全部转为大写的新字符串

    String toLowerCase():返回字母全部转为小写的新字符串

  • String concat(String another):返回拼接字符串

  • String replace(char oldChar, char newChar):替换字符串中的元素

    String str1 = "Foolish cultists";
    String str2 = str1.replace("cultists", "believers");	//str1不变,str2为改变的值
  • String[] split(String regex):分割字符串。

    对于某些分割字符,我们需要转义

    String str1 = "aaa,bbb,ccc";
    String[] strs1 = str1.split(",");		//这个场合,strs = {"aaa", "bbb", "ccc"};4
    String str2 = "aaa\bbb\ccc";
    String[] strs2 = str2.split("\\");		//"\" 是特殊字符,需要转义为 "\\"
  • int compareTo(String another):按照字典顺序比较两个字符串(的大小)。

    返回出现第一处不同的字符的编号差。前面字符相同,长度不同的场合,返回那个长度差。

    String str1 = "ccc";
    String str2 = "ca";
    String str3 = "ccc111abc";
    int n1 = str1.compareTo(str2);			//此时 n1 = 'c' - 'a' = 2
    int n2 = str1.compareTo(str3);			//此时 n2 = str1,length - str3.length = -6
    int n3 = str1.compareTo(str1);			//此时 n3 = 0
  • char[] toCharArray():转换成字符数组

    byte[] getBytes():字符串转为字节数组

  • String String.format(String format, Object... args):(静态方法)格式字符串

    String name = "Roin";
    String age = "1M";
    String state = "computer";
    String formatStr = "I am %s, I am %s old, I am a %s";
    String str = String.format(formatStr, name, age, state);
    //其中 %s 是占位符。此时,str = "I am Roin, I am 1M old, I am a computer";
    //%s 表示字符串替换;%d 表示整数替换;#.2f 表示小数(四舍五入保留2位)替换;%c 表示字符替换
  • String join(deli, ele...):拼接字符串(ele...),以 deli 间隔。

  • boolean startsWith(str):测试 str 是否为当前字符串的前缀

  • String repeat(int n):返回该字符串重复 n 次的结果

12.3 StringBuffer

java.lang.StringBuffer 代表可变的字符序列。可以对字符串内容进行增删。

很多方法和 String 相同,但 StringBuffer 是可变长度。同时,StringBuffer 是一个容器

  1. StringBuffer 的直接父类是 AbstractStringBuffer
  2. StringBuffer 实现了 Serialiazable,可以串行化
  3. 在父类中,AbstractStringBuffer 有属性 char[] value 不是 final
  4. StringBuffer 是一个 final 类,不能被继承

String 对比 StringBuffer

  • String 保存字符串常量,其中的值不能更改。每次更新实际上是更改地址,效率较低
  • StringBuffer 保存字符串变量,里面的值可以更改。每次更新是更新内容,不用每次更新地址。

12.3.1 StringBuffer 构造方法

  1. 无参构造

    StringBuffer strb1 = new StringBuffer();

    创造一个 16 位容量的空 StringBuffer

  2. 传入字符串构造

    String str1 = "abcabc";
    StringBuffer strb2 = new StringBuffer(str1);

    (上例)创造一个 str1.length + 16 容量的 StringBuffer

  3. 指定容量构造

    StringBuffer strb3 = new StringBuffer(3);

    (上例)创造一个 3 容量的空 StringBuffer

12.3.2 StringStringBuffer的转换

  1. StringBuffer

    String str1 = "abcabc";
    StringBuffer strb1 = new StringBuffer(str1);	//方法1(构造器)
    StringBuffer strb1 = new StringBuffer();		
    strb1 = strb1.append(str1);						//方法2(先空再append)
  2. String

    String str2 = strb1.toString();					//方法1(toString)
    String str3 = new String(strb1);				//方法2(构造器)

12.3.3 StringBuffer 的常用方法

  • append(char c):增加

    append(String s) 参数也能是字符串

    特别的,append(null); 的场合,等同于 append("null");

  • delete(start, end):删减 [start, end) 的内容

  • replace(start, end, string):将 start 与 end 间的内容替换为 string

  • indexOf:查找指定字符串第一次出现时的索引。没找到的场合返回 -1

  • insert:在指定索引位置之前插入指定字符串

  • length():返回字符长度

    capacity():返回当前的容量

    String 类对象分配内存时,按照对象中所含字符个数等量分配。

    StringBuffer 类对象分配内存时,除去字符所占空间外,会另加 16 字符大小的缓冲区。

    对于 length() 方法,返回的是字符串长度。对于 capacity() 方法,返回的是 字符串 + 缓冲区 的大小。

12.4 StringBuilder

一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,但不保证同步(有线程安全问题)。该类被设计成 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先使用该类。因为在大多数实现中,它比起 StringBuffer 要快。

StringBuilder 是的主要操作是 appendinsert 方法。可以重载这些方法,以接受任意类型的数据。

  1. StringBuilder 也继承了 AbstractStringBuffer

  2. StringBuilder 也实现了 Serialiazable,可以串行化

  3. 仍然是在父类中有属性 char[] value ,而且不是 final

  4. StringBuilder 也是一个 final 类,不能被继承

  5. StringBuilder 的方法,没有做互斥的处理(没有 synchronize),故而存在线程安全问题

12.4.1 StringStringBufferStringBuilder 的对比

  1. StringBuilderStringBuffer 类似,均代表可变字符序列,而且方法也一样

  2. String:不可变字符序列,效率低,但复用率高

  3. StringBuffer:可变字符序列,效率较高,线程安全

  4. StringBuilder:可变字符序列,效率最高,存在线程安全问题

  5. String 为何效率低:

    String str1 = "aa";					//创建了一个字符串
    for(int n = 0; n < 100; n++){		
    	str1 += "bb";					//这里,原先的字符串被丢弃,创建新字符串
    }									//多次执行后,大量副本字符串留在内存中
    									//导致效率降低,也会影响程序性能

    如上,对 String 大量修改的场合,不要使用 String

12.5 Math

  • Math.multiplyExact(int n1, int n2):进行乘法运算,返回运算结果

    通常的乘法 n1 * n2 在结果大于那个数据类型存储上限时,可能返回错误的值。

    使用此方法,结果大于那个数据类型存储上限时,会抛出异常

    Math.addExact(int n1, int n2):加法

    Math.subtractExact(int n1, int n2):减法

    Math.incrementExact(int n1):自增

    Math.decrementExact(int n1):自减

    Math.negateExact(int n1, int n2):改变符号

  • Math.abs(n):求绝对值,返回 |n1|

  • Math.pow(n, i):求幂,返回 n3 ^ i

  • Math.ceil(n):向上取整,返回 >= n3 的最小整数(转成double)

  • Math.floor(n):向下取整,返回 <=n4 的最小整数(转成double)

  • Math.floorMod(int n1, int n2):返回 n1 除以 n2 的余数

    n1 % n2 的场合,返回的可能是负数,而不是数学意义上的余数

  • Math.round(n):四舍五入,相当于 Math.floor(n5 + 0.5)

  • Math.sqrt(n):求开方。负数的场合,返回 NaN

  • Math.random():返回一个 [0, 1) 区间的随机小数

  • Math.sin(n):正弦函数

    Math.cos(n):余弦函数

    Math.tan(n)Math.atan(n)Math.atan2(n)

    要注意,上述方法传入的参数是 弧度值

    要得到一个角度的弧度值,应使用:Math.toRadians(n)

  • Math.exp(n):e 的 n 次幂

    Math.log10(n):10 为底的对数

    Math.log():自然对数

  • Math.PI:圆周率的近似值

    Math.E:e 的近似值

12.6 Arrays

  • Arrays.toString():返回数组的字符串形式

    int[] nums = {0, 1, 33};
    String str = Array.toString(nums);		//此时,str = "[0, 1, 33]"

    特别的,输入为 null 时返回 “null”

  • Arrays.sort(arr):排序

    因为数组是引用类型,使用 sort 排序后,会直接影响到实参。

    默认(自然排序)从小到大排序。

    Arrays.sort(arr, Comparator c):按照传入的比较器决定排序方法

    Integer[] nums;
    ...
    Comparator<Integer, Integer> c = new Comparator<Integer, Integer>(){
        @Override
        public int compare(Integer o1, Integer o2){
            return n2 - n1;						// 这个场合,变成从大到小排序
        }
    }
    Arrays.sort(nums, c);
  • Arrays.binarySearch(array, num):通过二分搜索法查找。前提是必须先排序。

    找不到的场合,返回 - (low + 1)。即,其应该在的位置的负值

    Integer[] nums2 = {-10, -5, -2, 0, 4, 5, 9};
    int index = Arrays.binarySearch(nums2, 7);	// 此时 index = -7
    											// 如果 7 存在,应该在第 7 个位置
  • Arrays.copyOf(arr, n):从 arr 中,复制 n 个元素(成为新的数组)。

    n > arr.length 的场合,在多余的位置添加 null。n < 0 的场合,抛出异常。

    该方法的底层使用的是 System.arraycopy

  • Arrays.fill(arr, o):用 o 填充 num 的所有元素。

  • Arrays.equals(arr1, arr2):比较两个数组元素是否完全一致(true/false

  • Arrays.asList(a, b, c, d):将输入数据转成一个 List 集合

12.7 System

  • System.exit(0):退出当前程序。0 表示一个状态,正常状态是 0

  • System.arraycopy(arr, 0, newArr, 0 ,3):复制数组元素。

    上例是:arr 自下标 0 起开始,向 newArr 自下标 0 开始,依次拷贝 3 个值

    这个方法比较适合底层调用。我们一般使用 Arrays.copyOf 来做

  • System.currentTimeMillis:返回当前时间距离 1970 - 1 - 1 的毫秒数

  • System.gc:运行垃圾回收机制

12.8 BigIntegerBigDecimal

BigInteger:适合保存更大的整数

BigDecimal:适合保存精度更大的浮点数

//用引号把大数变成字符串
BigInteger bigNum = new BigInteger("100000000000000000000000");

构造方法:

  • new BigInteger(String intStr):通过一个字符串构建大数
  • BigInteger BigInteger.valueOf(1):通过静态方法,让整数类型转成大数

另外,在对 BigIntegerBigDecimal 进行加减乘除的时候,需要使用对应方法

不能直接用 + - * /

常用方法:

  • BigInteger add(BigInteger):加法运算。返回新的大数

  • BigInteger subtract(BigInteger):减法

  • BigInteger multiply(BigInteger):乘法

  • BigInteger divide(BigInteger):除法运算

    该方法可能抛出异常。因为可能产生是无限长度小数。

    解决方法(保留分子精度):bigDecimal.divide(bD3, BigDecimal.ROUND_CELLING)

  • 一些常量:

    BigInteger.ONEBigInteger.ZEROBigInteger.TEN 分别是 1、0、10

    one 就是英文的 1,zero 就是英文的 0……这个大家都懂的吧?

12.9 日期类

12.9.1 第一代日期类

Date:精确到毫秒,代表特定瞬间。这里的是 java.util.Date

SimpleDateFormat:格式和解析日期的类

  1. Date d1 = new Date();:调用默认无参构造器,获取当前系统时间。

    默认输出日期格式是国外的格式,因此通常需要进行格式转换

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH.mm.ss");
    String dateFormated = sdf.(d1);							//日期转成指定格式。
  2. 通过指定毫秒数得到时间:

    Date d2 = new Date(10000000000);
  3. 把一个格式化的字符串转成对应的 Date:

    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH点mm分 E");
    Date d3 = sdf2.parse("2021年12月22日 00点03分 星期三");

    这个场合,给定的字符串格式应和 sdf2 格式相同,否则会抛出异常

12.9.2 第二代日期类

Calendar:构造器是私有的,要通过 getInstance 方法获取实例

  1. Calendar 是一个抽象类,其构造器私有

    Calendar c1 = Calendar.genInstance();				//获取实例的方法
  2. 提供大量方法和字段提供给程序员使用

    • c1.get(Calendar.YEAR):获取年份数

    • c1.get(Calendar.MONTH):获取月份数

      特别的,实际月份是 返回值 +1。因为 Calendar 的月份是从 0 开始编号的

    • c1.get(Calendar.DAY_OF_MONTH):获取日数

    • c1.get(Calendar.HOUR):获取小时数(12小时制)

      c1.get(Calendar.HOUR_OF_DATE):获取小时数(24小时制)

    • c1.get(Calendar.MINUTE):获取分钟数

    • c1.get(Calendar.SECOND):获取秒数

    Calendar 没有专门的格式化方法,需要程序员自己组合来显示

12.9.3 第三代日期类

JDK 1.0 加入的 Date 在 JDK 1.1 加入 Calendar 后已被弃用

然而,Calendar 也存在不足:

  1. 可变性:像日期和实际这样的类应该是不可改变的
  2. 偏移性:年份都是从 1900 年开始,月份都是从 0 开始
  3. 格式化:只对 Date 有用,对 Calendar 没用
  4. 其他问题:如不能保证线程安全,不能处理闰秒(每隔 2 天多 1 秒)等

于是,在 JDK 8 加入了以下新日期类:

  • LocalDate:只包含 日期(年月日),可以获取 日期字段
  • LocalTime:只包含 时间(时分秒),可以获取 时间字段
  • LocalDateTime:包含 日期 + 时间,可以获取 日期 + 时间字段
  • DateTimeFormatter:格式化日期
  • Instant:时间戳
  1. 使用 now() 方法返回当前时间的对象

    LocalDateTime ldt = LocalDateTime.now();				//获取当前时间
  2. 获取各字段方法:

    • ldt.getYear();:获取年份数

    • ldt.getMonth();:获取月份数(英文)

      ldt.getMonthValue();:获取月份数(数字)

    • ldt.getDayOfMonth();:获取日数

    • LocalDateTime ldt2 = ldt.plusDays(100);:获取 ldt 时间 100 天后的时间实例

    • LocalDateTime ldt3 = ldt.minusHours(100);:获取 ldt 时间 100 小时前的时间实例

  3. 格式化日期:

    DateTimeFormatter dtf = new DateTimeFormatter("yyyy.MM.dd HH.mm.ss");
    String date = dtf.format(ldt);							//获取格式化字符串
  4. InstantDate 类似

    • 获取当前时间戳:Instant instant = Instant.now();

    • 转换为 DateDate date = Date.form(instant);

    • Date 转换:Instant instant = date.toInstant;

12.10 泛型

泛型(generic):又称 参数化类型。是JDK 5 出现的新特性。解决数据类型的安全性问题。

在类声明或实例化时只要制定好需要的具体类型即可。

举例说明:

Properties<Person> prop = new Properties<Person>();

上例表示存放到 prop 中的必须是 Person 类型。

如果编译器发现添加类型不符合要求,即报错。

遍历时,直接取出 Person 而非 Object

  1. 编译时,检查添加元素的类型。可以保证如果编译时没发出警告,运行就不会产生 ClassCastException 异常。提高了安全性,使代码更加简洁、健壮。

  2. 也减少了转换的次数,提高了效率。

  3. 泛型的作用是:可以在类声明是通过一个标识表示类中某个属性的类型,或某个方法返回值的类型,或参数类型。

    class P<E> {
    	E e;				//E 表示 e 的数据类型,在定义 P类 时指定。在编译期间即确认类型
    	public P(E e){		//可作为参数类型
    		this.e = e;
    	}
    	public E doSth(){	//可作为返回类型
    		return this.e;
    	}
    }

    实例化时指定 E 的类型,编译时上例所有 E 会被编译器替换为那个指定类型

#使用方法:

  • 声明泛型:

    interface InterfaceName<T> {...}
    class ClassName<A, B, C, D> {...}

    上例 T、A、B、C、D 不是值,而是类型。可以用任意字母代替

  • 实例化泛型:

    List<String> strList = new ArrayList<String>();
    Iterator<Integer> iterator = vector.interator<Integer>();

    类名后面指定类型参数的值

注意细节:

  1. 泛型只能是引用类型

  2. 指定泛型具体类型后,可以传入该类型或其子类类型

  3. 在实际开发中往往简写泛型

    List<String> strList = new ArrayList<>();

    编译器会进行类型推断,右边 < > 内容可以省略

  4. 实例化不写泛型的场合,相当于默认泛型为 Object

#自定义泛型类 · 接口:

class Name<A, B...> {...}				//泛型标识符 可有多个,一般是单个大写字母表示

这就是自定义泛型啊

  1. 普通成员可以使用泛型(属性、方法)

  2. 泛型类的类型,是在创建对象时确定的。

    因此:静态方法中不能使用类的泛型;使用泛型的数组,也不能初始化。

  3. 创建对象时不指定的场合,默认 Object。建议还是写上 <Object>,大气,上档次

  4. 自定义泛型接口

    interface Name<T, R...> {...}

    泛型接口,其泛型在 继承接口 或 实现接口 时确定。

#自定义泛型方法:

修饰符 <T, R...> 返回类型 方法名(形参) {...}
  1. 可以定义在普通类中,也可以定义在泛型类中

  2. 当泛型方法被调用时,类型会确定

  3. 以下场合

    Class C<T> {
    	public void cMethord(T t){		
    	}
    }

    没有 < >,不是泛型方法,而是使用了泛型的普通方法

#泛型继承:

  1. 泛型不具有继承性
  2. <?>:支持任意泛型类型
  3. <? extends A>:支持 A 及 A的子类,规定了泛型的上限
  4. <? super B>:支持 B 及 B 的父类,规定了泛型的下限

<Java>12 常用类
https://i-melody.github.io/2021/12/19/Java/入门阶段/12 常用类/
作者
Melody
发布于
2021年12月19日
许可协议