Java核心类
Java官方文档:https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/String.html
String
字符串在String
内部是通过一个char[]
数组表示的
String s2 = new String(new char[] {'H', 'e', 'l', 'l', 'o', '!'});
各类函数的使用可参考官方文档
String
和char[]
类型可以互相转换,方法是:
char[] cs = "Hello".toCharArray(); // String -> char[] String s = new String(cs); // char[] -> String
StringBuilder
虽然String可以直接拼接字符串。但是,在循环中,每次循环都会创建新的字符串对象,然后扔掉旧的字符串。这样,绝大部分字符串都是临时对象,不但浪费内存,还会影响GC效率。
StringBuilder
,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder
中新增字符时,不会创建新的临时对象
StringBuilder sb = new StringBuilder(1024); for (int i = 0; i < 1000; i++) { sb.append(','); sb.append(i); } String s = sb.toString();
并且StringBuilder支持链式操作:
var sb = new StringBuilder(1024); sb.append("Mr ") .append("Bob") .append("!") .insert(0, "Hello, ");
StringBuffer
,这是Java早期的一个StringBuilder
的线程安全版本,它通过同步来保证多个线程操作StringBuffer
也是安全的,但是同步会带来执行速度的下降。
包装类
Java核心库为每种基本类型都提供了对应的包装类型:boolean Boolean; type Type; short Short; int Integer; long Long; float Float; double Double; char Character。
int i = 100; Integer n = Integer.valueOf(i); int x = n.intValue(); Integer n = 100; // 编译器自动使用Integer.valueOf(int) int x = n; // 编译器自动使用Integer.intValue() Integer n = null; int i = n; //报错 基本类型不允许为null
所有的包装类型都是不变类。我们查看Integer
的源码可知,它的核心代码如下:
public final class Integer { private final int value; }
Enum
通过枚举定义的类和class定义的类没有任何区别。enum
定义的类型就是class
,只不过它有以下几个特点:
- 定义的
enum
类型总是继承自java.lang.Enum
,且无法被继承; - 只能定义出
enum
的实例,而无法通过new
操作符创建enum
的实例; - 定义的每个实例都是引用类型的唯一实例;
- 可以将
enum
类型用于switch
语句。
enum Weekday { SUN, MON, TUE, WED, THU, FRI, SAT; } Weekday day = Weekday.SUN; day == Weekday.SAT || day == Weekday.SUN //true
如果枚举包含数字和中文可以如下定义和使用:
public class Main { public static void main(String[] args) { Weekday day = Weekday.SUN; if (day.dayValue == 6 || day.dayValue == 0) { System.out.println("Today is " + day + ". Work at home!"); } else { System.out.println("Today is " + day + ". Work at office!"); } } } enum Weekday { MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六"), SUN(0, "星期日"); public final int dayValue; private final String chinese; private Weekday(int dayValue, String chinese) { this.dayValue = dayValue; this.chinese = chinese; } @Override public String toString() { return this.chinese; } }
BigInteger
表示任意大小的整数。BigInteger
内部用一个int[]
数组来模拟一个非常大的整数;从Number继承
BigInteger bi = new BigInteger("1234567890"); System.out.println(bi.pow(5)); // 2867971860299718107233761438093672048294900000
对BigInteger
做运算的时候,只能使用实例方法,例如,加法运算:
BigInteger i1 = new BigInteger("1234567890"); BigInteger i2 = new BigInteger("12345678901234567890"); BigInteger sum = i1.add(i2); // 12345678902469135780
BigDecimal
和BigInteger
类似,BigDecimal
可以表示一个任意大小且精度完全准确的浮点数。也是继承至Number
BigDecimal
用scale()
表示小数位数,例如:
BigDecimal d1 = new BigDecimal("123.45"); System.out.println(d1.scale()); // 2,两位小数
通过BigDecimal
的stripTrailingZeros()
方法,可以将一个BigDecimal
格式化为一个相等的,但去掉了末尾0的BigDecimal
:
BigDecimal d1 = new BigDecimal("123.4500"); BigDecimal d2 = d1.stripTrailingZeros(); //123.45
可以对一个BigDecimal
设置它的scale setscale()
,如果精度比原始值低,那么按照指定的方法进行四舍五入或者直接截断:
BigDecimal d1 = new BigDecimal("123.456789"); BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP); // 四舍五入,123.4568
对BigDecimal
做加、减、乘时,精度不会丢失,但是做除法时,存在无法除尽的情况,这时,就必须指定精度以及如何进行截断:
BigDecimal d1 = new BigDecimal("123.456"); BigDecimal d2 = new BigDecimal("23.456789"); BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小数并四舍五入 BigDecimal d4 = d1.divide(d2); // 报错:ArithmeticException,因为除不尽
BigDecimal
做除法的同时求余数; 调用divideAndRemainder()
方法时,返回的数组包含两个BigDecimal
,分别是商和余数,其中商总是整数,余数不会大于除数。我们可以利用这个方法判断两个BigDecimal
是否是整数倍数:
BigDecimal n = new BigDecimal("12.345"); BigDecimal m = new BigDecimal("0.12"); BigDecimal[] dr = n.divideAndRemainder(m); System.out.println(dr[0]); // 102 System.out.println(dr[1]); // 0.105
在比较两个BigDecimal
的值是否相等时,要特别注意,使用equals()
方法不但要求两个BigDecimal
的值相等,还要求它们的scale()
相等:
BigDecimal d1 = new BigDecimal("123.456"); BigDecimal d2 = new BigDecimal("123.45600"); System.out.println(d1.equals(d2)); // false,因为scale不同 System.out.println(d1.equals(d2.stripTrailingZeros())); // true,因为d2去除尾部0后scale变为2 System.out.println(d1.compareTo(d2)); // 0
必须使用compareTo()
方法来比较,它根据两个值的大小分别返回负数、正数和0
,分别表示小于、大于和等于。
如果查看BigDecimal
的源码,可以发现,实际上一个BigDecimal
是通过一个BigInteger
和一个scale
来表示的,即BigInteger
表示一个完整的整数,而scale
表示小数位数:
public class BigDecimal extends Number implements Comparable<BigDecimal> { private final BigInteger intVal; private final int scale; }
Math
Math
类就是用来进行数学计算的,它提供了大量的静态方法来便于我们实现数学计算
Random
Random
用来创建伪随机数。所谓伪随机数,是指只要给定一个初始的种子,产生的随机数序列是完全一样的。
创建Random
实例时,如果不给定种子,就使用系统当前时间戳作为种子,因此每次运行时,种子不同,得到的伪随机数序列就不同
SecureRandom
用来创建安全的随机数,SecureRandom
无法指定种子,它使用RNG(random number generator)算法