Java 常用类

Java 常用类
sinarcsinx包装类
包装类(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 |
装箱和拆箱
手动装箱和拆箱(JDK 5 以前)
1
2
3
4int n1 = 100;
Integer integer = new Integer(n1); // 手动装箱
Integer integer2 = Integer.valueOf(n1); // 手动装箱
int i = integer.intValue(); // 手动拆箱自动装箱和拆箱(JDK 5 以后)
1
2
3n2 = 200;
Integer integer3 = n2; // 自动装箱
int j = integer3; // 自动拆箱虽然可以自动装箱、拆箱,但使用 == 直接比较两个包装类时,仍然是比较其地址。以下比较通常会失败:
1
2
3Integer ia = 1000;
Integer ib = 1000;
System.out.print(ia == ib); // false但,Java 实现仍有可能使其成立。Byte、Boolean 以及 Short、Integer 中 [-128, 127] 间的值已被包装到固定的对象中。对他们的比较可以成功。
1
2
3Integer ia = 127;
Integer ib = 127;
System.out.print(ia == ib); // true由此可见,使用 == 直接比较两个包装类会带来不确定性。尽量使用 equals 方法对包装类进行比较。
装箱与拆箱是 编译器 的工作。在生成可执行的字节码文件时,编译器已经插入了必要的方法调用。
包装类和 String 的相互转换
包装类转
String:1
2
3
4>Integer integer = 100;
>String str1 = integer + ""; //方法1(自动拆箱)
>String str2 = integer.toString(); //方法2(toString方法)
>String str3 = String.valueOf(integer); //方法3(自动拆箱)String转包装类:1
2
3String str4 = "100";
Integer integer2 = Integer.parseInt(str4); //方法1(自动装箱)
Integer integer3 = new Integer(str4); //方法2(构造器)
包装类的常用方法
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 内容转为 intDouble.parseDouble(string)Integer.toBinaryString(int):将数字转为 2 进制表示的字符串Integer.toHexString(int):将数字转为 16 进制表示的字符串Integer.toOctalString(int):将数字转为 8 进制表示的字符串特别地,浮点数类型的包装类只有转成 16 进制的方法。而 Short、Byte 及其他包装类无此方法
int Integer.bitCount(i int):统计指定数字的二进制格式中 1 的数量
strictfp 关键字
由于不同处理器对于浮点数寄存采取不同策略(有些处理器使用 64 位寄存 double,有些则是 80 位),对于浮点数的运算在不同平台上可能出现不同结果。
使用 strictfp 关键字标记的方法或类中,所有指令都会使用严格统一的浮点数运算。
比如,把 main 方法标记为 strictfp
1 | public static strictfp void main(String[] args) { |
String 类
String对象用于保存字符串,也就是一组字符序列字符串常量对象是用双引号扩起的字符序列。例如
"你好"字符串的字符使用 Unicode 字符编码。一个字符(不论字母汉字)占 2 字节
常用构造器:
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个字符
String实现了接口Serializable和Comparable,可以 串行化和 比较大小串行化:即,可以被网络传输,也能保存到文件
String是final类,不能被继承String有属性private final char[] value;用于存放字符串内容。value是final属性。其在栈中的地址不能修改,但堆中的内容可以修改。
String 构造方法
直接指定
1
String str1 = "哈哈哈";
该方法:先从常量池看是否有
"哈哈哈"数据空间。有的场合,指向那个空间;否则重新创建然后指向。这个方法,
str1指向 常量池中的地址。构造器
1
String str2 = new String("嘿嘿嘿");
该方法:先在堆中创建空间,里面维护一个
value属性,指向 或 创建后指向 常量池的"嘿嘿嘿"空间。这个方法,
str2指向 堆中的地址
字符串的特性
常量相加,看的是池
1
String str1 = "aa" + "bb"; //常量相加,看的是池
上例由于构造器自身优化,相当于
String str1 = "aabb";变量相加,是在堆中
1
2
3String a = "aa";
String b = "bb";
String str2 = a + b; //变量相加,是在堆中上例的底层是如下代码
1
2
3
4StringBuilder sb = new StringBuilder();
sb.append(a);
sb.append(b);
str2 = sb.toString(); //sb.toString():return new String(value, 0, count);
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():获取字符(代码单元)的个数—— 代码单元,见 Java 变量
IntStream codePoints():返回字符串中全部码点构成的流long codePoints().count():返回真正长度(码点数量)int indexOf(String str):获取字符(串)在字符串中第一次出现的索引。如果找不到,返回 -1int indexOf(int char)参数也可以传入一个 int。由于自动类型转换的存在,也能填入 charint indexOf(String str, int index):从 index 处(包含)开始查找指定字符(串)int lastIndexOf(String str):获取字符在字符串中最后一次出现的索引。如果找不到,返回 -1String 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):替换字符串中的元素1
2String str1 = "Foolish cultists";
String str2 = str1.replace("cultists", "believers"); //str1不变,str2为改变的值String[] split(String regex):分割字符串。对于某些分割字符,我们需要转义
1
2
3
4String 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):按照字典顺序比较两个字符串(的大小)。返回出现第一处不同的字符的编号差。前面字符相同,长度不同的场合,返回那个长度差。
1
2
3
4
5
6String 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 = 0char[] toCharArray():转换成字符数组byte[] getBytes():字符串转为字节数组String String.format(String format, Object... args):(静态方法)格式字符串1
2
3
4
5
6
7String 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 次的结果
StringBuffer 类
java.lang.StringBuffer代表可变的字符序列。可以对字符串内容进行增删。很多方法和
String相同,但StringBuffer是可变长度。同时,StringBuffer是一个容器
StringBuffer的直接父类是AbstractStringBufferStringBuffer实现了Serialiazable,可以串行化- 在父类中,
AbstractStringBuffer有属性char[] value不是final StringBuffer是一个final类,不能被继承
String 对比 StringBuffer
String保存字符串常量,其中的值不能更改。每次更新实际上是更改地址,效率较低StringBuffer保存字符串变量,里面的值可以更改。每次更新是更新内容,不用每次更新地址。
StringBuffer 构造方法
无参构造
1
StringBuffer strb1 = new StringBuffer();
创造一个 16 位容量的空
StringBuffer传入字符串构造
1
2String str1 = "abcabc";
StringBuffer strb2 = new StringBuffer(str1);(上例)创造一个 str1.length + 16 容量的
StringBuffer指定容量构造
1
StringBuffer strb3 = new StringBuffer(3);
(上例)创造一个 3 容量的空
StringBuffer
String 和 StringBuffer的转换
转
StringBuffer1
2
3
4String str1 = "abcabc";
StringBuffer strb1 = new StringBuffer(str1); //方法1(构造器)
StringBuffer strb1 = new StringBuffer();
strb1 = strb1.append(str1); //方法2(先空再append)转
String1
2String str2 = strb1.toString(); //方法1(toString)
String str3 = new String(strb1); //方法2(构造器)
StringBuffer 的常用方法
append(char c):增加append(String s)参数也能是字符串特别的,
append(null);的场合,等同于append("null");delete(start, end):删减 [start, end) 的内容replace(start, end, string):将 start 与 end 间的内容替换为 stringindexOf:查找指定字符串第一次出现时的索引。没找到的场合返回 -1insert:在指定索引位置之前插入指定字符串length():返回字符长度capacity():返回当前的容量String 类对象分配内存时,按照对象中所含字符个数等量分配。
StringBuffer 类对象分配内存时,除去字符所占空间外,会另加 16 字符大小的缓冲区。
对于
length()方法,返回的是字符串长度。对于capacity()方法,返回的是 字符串 + 缓冲区 的大小。
StringBuilder 类
一个可变的字符序列。此类提供一个与
StringBuffer兼容的 API,但不保证同步(有线程安全问题)。该类被设计成StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先使用该类。因为在大多数实现中,它比起StringBuffer要快。在
StringBuilder是的主要操作是append和insert方法。可以重载这些方法,以接受任意类型的数据。
StringBuilder也继承了AbstractStringBufferStringBuilder也实现了Serialiazable,可以串行化仍然是在父类中有属性
char[] value,而且不是finalStringBuilder也是一个final类,不能被继承StringBuilder的方法,没有做互斥的处理(没有synchronize),故而存在线程安全问题
String、StringBuffer、StringBuilder 的对比
StringBuilder和StringBuffer类似,均代表可变字符序列,而且方法也一样String:不可变字符序列,效率低,但复用率高StringBuffer:可变字符序列,效率较高,线程安全StringBuilder:可变字符序列,效率最高,存在线程安全问题String为何效率低:1
2
3
4
5String str1 = "aa"; //创建了一个字符串
for(int n = 0; n < 100; n++){
str1 += "bb"; //这里,原先的字符串被丢弃,创建新字符串
} //多次执行后,大量副本字符串留在内存中
//导致效率降低,也会影响程序性能如上,对
String大量修改的场合,不要使用String
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 ^ iMath.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):求开方。负数的场合,返回NaNMath.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 的近似值
Arrays 类
Arrays.toString():返回数组的字符串形式1
2int[] nums = {0, 1, 33};
String str = Array.toString(nums); //此时,str = "[0, 1, 33]"特别的,输入为 null 时返回 “null”
Arrays.sort(arr):排序因为数组是引用类型,使用 sort 排序后,会直接影响到实参。
默认(自然排序)从小到大排序。
Arrays.sort(arr, Comparator c):按照传入的比较器决定排序方法1
2
3
4
5
6
7
8
9Integer[] nums;
...
Comparator<Integer, Integer> c = new Comparator<Integer, Integer>(){
public int compare(Integer o1, Integer o2){
return n2 - n1; // 这个场合,变成从大到小排序
}
}
Arrays.sort(nums, c);Arrays.binarySearch(array, num):通过二分搜索法查找。前提是必须先排序。找不到的场合,返回 - (low + 1)。即,其应该在的位置的负值
1
2
3Integer[] 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.arraycopyArrays.fill(arr, o):用 o 填充num的所有元素。Arrays.equals(arr1, arr2):比较两个数组元素是否完全一致(true/false)Arrays.asList(a, b, c, d):将输入数据转成一个List集合
System 类
System.exit(0):退出当前程序。0 表示一个状态,正常状态是 0System.arraycopy(arr, 0, newArr, 0 ,3):复制数组元素。上例是:arr 自下标 0 起开始,向 newArr 自下标 0 开始,依次拷贝 3 个值
这个方法比较适合底层调用。我们一般使用
Arrays.copyOf来做System.currentTimeMillis:返回当前时间距离 1970 - 1 - 1 的毫秒数System.gc:运行垃圾回收机制
BigInteger 和 BigDecimal 类
BigInteger:适合保存更大的整数
BigDecimal:适合保存精度更大的浮点数
1 | //用引号把大数变成字符串 |
构造方法:
new BigInteger(String intStr):通过一个字符串构建大数BigInteger BigInteger.valueOf(1):通过静态方法,让整数类型转成大数
另外,在对 BigInteger 和 BigDecimal 进行加减乘除的时候,需要使用对应方法
不能直接用 + - * /
常用方法:
BigInteger add(BigInteger):加法运算。返回新的大数BigInteger subtract(BigInteger):减法BigInteger multiply(BigInteger):乘法BigInteger divide(BigInteger):除法运算该方法可能抛出异常。因为可能产生是无限长度小数。
解决方法(保留分子精度):
bigDecimal.divide(bD3, BigDecimal.ROUND_CELLING)一些常量:
BigInteger.ONE、BigInteger.ZERO、BigInteger.TEN分别是 1、0、10one 就是英文的 1,zero 就是英文的 0……这个大家都懂的吧?
日期类
第一代日期类
Date:精确到毫秒,代表特定瞬间。这里的是 java.util.Date
SimpleDateFormat:格式和解析日期的类
Date d1 = new Date();:调用默认无参构造器,获取当前系统时间。默认输出日期格式是国外的格式,因此通常需要进行格式转换
1
2SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH.mm.ss");
String dateFormated = sdf.(d1); //日期转成指定格式。通过指定毫秒数得到时间:
1
Date d2 = new Date(10000000000);
把一个格式化的字符串转成对应的 Date:
1
2SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd日 HH点mm分 E");
Date d3 = sdf2.parse("2022年12月21日 00点03分 星期三");这个场合,给定的字符串格式应和
sdf2格式相同,否则会抛出异常
第二代日期类
Calendar:构造器是私有的,要通过 getInstance 方法获取实例
Calendar 是一个抽象类,其构造器私有
1
Calendar c1 = Calendar.genInstance(); //获取实例的方法
提供大量方法和字段提供给程序员使用
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 没有专门的格式化方法,需要程序员自己组合来显示
第三代日期类
JDK 1.0 加入的 Date 在 JDK 1.1 加入 Calendar 后已被弃用
然而,Calendar 也存在不足:
- 可变性:像日期和实际这样的类应该是不可改变的
- 偏移性:年份都是从 1900 年开始,月份都是从 0 开始
- 格式化:只对 Date 有用,对 Calendar 没用
- 其他问题:如不能保证线程安全,不能处理闰秒(每隔 2 天多 1 秒)等
于是,在 JDK 8 加入了以下新日期类:
- LocalDate:只包含 日期(年月日),可以获取 日期字段
- LocalTime:只包含 时间(时分秒),可以获取 时间字段
- LocalDateTime:包含 日期 + 时间,可以获取 日期 + 时间字段
- DateTimeFormatter:格式化日期
- Instant:时间戳
使用
now()方法返回当前时间的对象1
LocalDateTime ldt = LocalDateTime.now(); //获取当前时间
获取各字段方法:
ldt.getYear();:获取年份数ldt.getMonth();:获取月份数(英文)ldt.getMonthValue();:获取月份数(数字)ldt.getDayOfMonth();:获取日数LocalDateTime ldt2 = ldt.plusDays(100);:获取 ldt 时间 100 天后的时间实例LocalDateTime ldt3 = ldt.minusHours(100);:获取 ldt 时间 100 小时前的时间实例…
格式化日期:
1
2DateTimeFormatter dtf = new DateTimeFormatter("yyyy.MM.dd HH.mm.ss");
String date = dtf.format(ldt); //获取格式化字符串Instant和Date类似获取当前时间戳:
Instant instant = Instant.now();转换为
Date:Date date = Date.form(instant);由
Date转换:Instant instant = date.toInstant;
泛型
泛型(generic):又称 参数化类型。是JDK 5 出现的新特性。解决数据类型的安全性问题。
在类声明或实例化时只要制定好需要的具体类型即可。
举例说明:
1 | Properties<Person> prop = new Properties<Person>(); |
上例表示存放到
prop中的必须是Person类型。如果编译器发现添加类型不符合要求,即报错。
遍历时,直接取出
Person而非Object
编译时,检查添加元素的类型。可以保证如果编译时没发出警告,运行就不会产生 ClassCastException 异常。提高了安全性,使代码更加简洁、健壮。
也减少了转换的次数,提高了效率。
泛型的作用是:可以在类声明是通过一个标识表示类中某个属性的类型,或某个方法返回值的类型,或参数类型。
1
2
3
4
5
6
7
8
9class P<E> {
E e; //E 表示 e 的数据类型,在定义 P类 时指定。在编译期间即确认类型
public P(E e){ //可作为参数类型
this.e = e;
}
public E doSth(){ //可作为返回类型
return this.e;
}
}实例化时指定 E 的类型,编译时上例所有 E 会被编译器替换为那个指定类型
使用方法:
声明泛型:
1
2interface InterfaceName<T> {...}
class ClassName<A, B, C, D> {...}上例 T、A、B、C、D 不是值,而是类型。可以用任意字母代替
实例化泛型:
1
2List<String> strList = new ArrayList<String>();
Iterator<Integer> iterator = vector.interator<Integer>();类名后面指定类型参数的值
注意细节:
泛型只能是引用类型
指定泛型具体类型后,可以传入该类型或其子类类型
在实际开发中往往简写泛型
1
List<String> strList = new ArrayList<>();
编译器会进行类型推断,右边
< >内容可以省略实例化不写泛型的场合,相当于默认泛型为
Object
自定义泛型类 · 接口:
1 | class Name<A, B...> {...} //泛型标识符 可有多个,一般是单个大写字母表示 |
这就是自定义泛型啊
普通成员可以使用泛型(属性、方法)
泛型类的类型,是在创建对象时确定的。
因此:静态方法中不能使用类的泛型;使用泛型的数组,也不能初始化。
创建对象时不指定的场合,默认 Object。建议还是写上
<Object>,大气,上档次自定义泛型接口
1
interface Name<T, R...> {...}
泛型接口,其泛型在 继承接口 或 实现接口 时确定。
自定义泛型方法:
1 | 修饰符 <T, R...> 返回类型 方法名(形参) {...} |
可以定义在普通类中,也可以定义在泛型类中
当泛型方法被调用时,类型会确定
以下场合
1
2
3
4Class C<T> {
public void cMethord(T t){
}
}没有
< >,不是泛型方法,而是使用了泛型的普通方法
泛型继承:
- 泛型不具有继承性
<?>:支持任意泛型类型<? extends A>:支持 A 及 A的子类,规定了泛型的上限<? super B>:支持 B 及 B 的父类,规定了泛型的下限







