常用类
常用类是比较重要的,在面试的时候也是问的比较多的
包装类
针对八种基本的数据类型,定义了相应的引用类型,这些基本数据的引用类型叫做包装类
这些基本的数据类型,有了类的特点,就可以调用类中的方法
| 基本数据类型 | 包装类 |
|---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
其中,前面两个包装类的父类是Object类型;后面六个包装类的父类是Number,Numer在继承Object基类
包装类和基本数据类型的转换
- 在
jdk5之前的手动装箱和拆箱方式,装箱:基本数据类型转换为包装类型,反之拆箱为包装类型转换为基本数据类型 jdk5以后(含jdk5)的自动装箱和拆箱方式,自动装箱的底层调用的是valueOf方法,如:Interger.valueOf()
public class Wrapper {
public static void main(String[] args) {
// 演示int <---> Integer 的装箱和拆箱
// jdk5之前是手动装箱和拆箱
int n1 = 100;
// 手动装箱 int ---> Integer
Integer integer1 = new Integer(n1);//或者使用 Integer integer1=Integer.valueOf(n1);
// 手动拆箱 int <--- Integer
int n = integer1.intValue();
// 在jdk5以后(包括5),就可以自动装箱和自动拆箱
int n2 = 200;
// 自动装箱 int ---> Integer
Integer integer2 = n2; // 底层调用的是Integer.valueOf方法
// 自动拆箱 int <--- Integer
int n = integer2; // 底层还是调用integer2.intValue()方法
}
}上述代码以
int来举例,其他的包装类的装箱和拆箱方式类似
经典面试题:
// 下面输出的内容是什么:
Object obj1 = ture ? new Integer(1) : new Double(2.0);
System.out.println(obj1); // 1.0
// ture ? new Integer(1) : new Double(2.0)这一块是一个整体,其精度最高的是Double,因此会提升优先级
// 即三元运算符是一个整体Integer类的经典面试题:
// 下面代码输出什么
public void method() {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j); // false 两个不同的对象,只要是new,出来的就是不同对象
// 主要是看范围,如果传入的值为-128到127之间,是直接返回的,没有创建对象
Integer m = 1; // 底层是Integer.valueOf(1); 我们需要看源码
Integer n = 1; // 底层是Integer.valueOf(1);
System.out.println(m == n); // true
Integer x = 128;
Integer y = 128;
System.out.println(x == y); // false 创建了对象,所有不相等
Integer a = 127;
Integer b = new Integer(127);
System.out.println(a == b); // false b是对象
// 只要有基本数据类型的,就只要判断值是否相等
Integer c = 127;
int d = 127;
System.out.println(c == d); // true
Integer h = 128;
int j = 128;
System.out.println(h == j); // true
}对于Integer.valueOf()的源码:
public static Integer valueOf(int i) {
// 如果传入的i在以下的范围内,就直接从数组返回(这个数组是在类加载的时候就创建好了的,类似于将缓存中的值直接给你),没有真正的创建对象,这个范围是-128 到 127,如果不在这个范围内,就new一个对象
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}包装类与String类型的相互转换
演示案例以Integer包装类和String类转换为例:
public class WrapperVSString {
public static void main(String[] args) {
// 包装类 ---> String类型
Integer i = 100; // 自动装箱
// 方式一:
String str1 = i + ""; // 这种情况对原先的i的数据类型没有影响
// 方式二:
String str2 = i.toString();
// 方式三:
String str3 = String.valueOf(i);
// 包装类 <--- String类型
String str = "123";
// 方式一
Integer i2 = Integer.parseInt(str); // 自动装箱
// 方式二:通过包装类中的构造器方法
Integer i3 = new Integer(str);
}
}包装类的常用方法
Integer包装类的常用方法:
Integer.MIN_VALUE:返回最小值Integer.MAX_VALUE:返回最大值
Character包装类的常用方法:
Character.isDigit():判断是不是数字Character.isLetter():判断是不是字母Character.isUpperCase():判断是不是大写字母Character.isLowerCase():判断是不是小写字母Character.isWhitespace():判断是不是空格Character.toUpperCase():转成大写Character.toLowerCase():转成小写
String类
String对象是用于保存字符串的,也就是一组字符序列
字符串常量对象是用双引号括起来的,如:"你好"
String name = "jlc";
// name为字符串变量
// "jlc"为字符串常量,是一个具体的值字符串的字符是使用Unicode字符编码,一个字符(不区分字母还是汉字)都是占两个字节
String类常见的构造器:(字符串类有很多的构造器)
String s1 = new String();String s2 = new String(String original);String s3 = new String(char[] a);String s4 = new String(char[] a, int startIndex, int count);String s5 = new String(byte[] b);
String类的继承关系:

String类继承于Object基类,同时实现了三个接口:
Serializable:实现了这个接口,表示对象可以串行化,意味着String对象可以在网络中传输Comparable:实现了这个接口,说明了String对象可以进行比较CharSequence:字符序列接口
String类是finaly类,即不能被其他类继承
String类中有属性:private final char value[]; 用于存放字符串内容,value是一个final类型,一旦被赋值了,就不可以进行改变(是指地址不可修改,指向了一个空间后,就不可以修改指向另一个空间)(同一个空间中的字符串内容是可以进行修改的)
String对象的两种创建方式:两种创建对象方式的机制是不一样的
直接赋值:
String s = "jlc";创建机制:先从常量池查看是否有
"jlc"s数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址调用构造器:
String s = new String("jlc");先在堆中创建空间,里面维护了
value属性,指向常量池的"jlc"空间。如果常量池没有"jlc",重新创建,如果有,直接通过value指向,最终指向的是堆中的空间地址
具体内存图:

String a = "abc";
String b = "abc";
System.out.println(a.equals(b)); // true 比较字符内容是否一样
System.out.println(a == b); // true 指向的地址是一样的,指向的是同一个对象
String a = new String("abc");
String b = new String("abc");
System.out.println(a.equals(b)); // true 比较字符内容是否一样
System.out.println(a == b); // false 指向的地址是不一样,指向堆中的不同对象
String a = "abc";
String b = new String("abc");
System.out.println(a.equals(b)); // true 比较字符内容是否一样
System.out.println(a == b); // false 指向的地址是不一样,指向堆中的不同对象,一个指向的常量池中的对象
System.out.println(a == b.intern()); // true b.intern()返回的是常量池中的地址
System.out.println(b == b.intern()); // false b是指向堆的,b.intern()返回的是常量池中的地址
// 知识点:当调用intern方法时,如果池已经包含一个等于此String对象的字符串(用equals(Object)方法确定),则返回常量池中的字符串。否则,将此String对象添加到常量池中,并返回此String对象的引用
// 总结:b.intern()方法最终返回的是常量池的地址(对象)Person p1 = new Person();
p1.name = "jlc";
Person p2 = new Person();
p2.name = "jlc";
System.out.println(p1.name.equals(p2.name)); // True 字符串内容一样
System.out.println(p1.name == p2.name); // True p1.name 和 p2.name 都是指向常量池中的"jlc"
System.out.println(p1.name == "jlc"); // True "jlc"的地址就是池中的具体值的地址 p1.name也指向池中的具体值的地址对象特性
String是一个final类,代表不可变的字符序列- 字符串是不可变的,一个字符串对象一旦被分配,其内容是不可变的
经典面试题:
String s1 = "hello";
s1 = "haha";创建了两个对象(字符串常量对象),先指向了"hello",后指向了"haha"
内存分布图:

String a = "hello" + "abc";
// 底层编译器会进行优化(判断创建的常量池对象,是否有引用指向),优化后等价于:String a = "helloabc";
// 所以创建了一个字符串常量对象String a = "hello";
String b = "abc";
// 1. 先创建一个 StringBuilder sb = StringBuilder()
// 2. 执行 sb.append("hello"); sb.append("abc");
// 3. 执行 String c = sb.toString(); 将字符串返回给c
// 最后其实是c指向堆中的对象(String)value[] --> 指向池中的"helloabc"
String c = a + b;底层是
StringBuilder sb = new StringBuilder();sb.append(a);sb.append(b);
sb是在堆中,并且append是在原来字符串的基础上进行追加的一个创建了三个对象,内存分布图:
重要规则:
String c1 = "ab" + "cd";常量相加,看的是池String c1 = a + b;变量相加,是在堆中
public class Test1 {
String str = new String("jlc");
final char[] ch = {'j', 'a', 'v', 'a'};
public void change(String str, char ch[]) {
str = "java";
ch[0] = 'h';
}
}
public static void main(String[] args) {
Test1 ex = new Test1();
ex.change(ex.str, ex.ch);
System.out.print(ex.str + "and"); // jlcand
System.out.println(ex.ch); // hava
}内存分析:

- 堆中有一个对象为
str,字符串对象指向堆中的一个value空间,这个地址指向池中的具体数据- 字符串数组,是放在堆中的,
ch属性指向堆中的空间- 生成的
ex对象指向堆中的空间- 在调用方法的时候,会在栈中开辟新栈
change,将实参ex.str赋值给了形参str;将实参ex.ch赋值给了形参ch,刚开始传递过来时,str也指向原先的地址空间str = "java";执行后,断掉原先的指向,重新指向到常量池中的java地址中ch一开始也是指向ex.ch指向的地址空间(堆中的数组)ch[0] = 'h';执行后,将第一个元素进行修改(修改字符数组的某个元素是合理的)- 当方法执行完后,
change栈就销毁了,就回到了主栈ex.str没有发生任何的变化,其值还是jlc;但是ex.ch的属性值第一个被修改了
常用方法
String类的方法是非常多大,我们需要掌握常用方法:
equals:判断内容是否相等(区分大小写)javaString str1 = "hello"; String str2 = "Hello"; System.out.println(str1.equals(str2)); // falseequalsIgnoreCase:判断内容是否相等(不区分大小写)length:获取字符串长度(获取字符的个数)javaString str = "Hello"; System.out.println(str.length()); // 5indexOf:获取某个字符在字符串中第一次出现的索引,索引从0开始,如果找不到,返回-1javaString str = "jlc@sdfds@efs"; int index = str.indexOf('@'); System.out.println(index); // 3 // 该方法除了是单个字符,还可以是字符串 System.out.println(str.indexOf("lc")); // 1lastIndexOf:获取某个字符在字符串中最后一次出现的索引,索引从0开始,如果找不到,返回-1substring:截取指定范围的子串javaString name = "hello,jlc"; System.out.println(name.substring(6)); // jlc 从索引为6的位置开始截取,到最后的字符 System.out.println(name.substring(0, 5)); // hello 截取指定开始索引和结束索引的字符(开始索引包括,结束索引不包括)trim:去掉前后空格charAt:获取某索引处的字符,注意不能使用Str[index]这个方式(不能将字符串当数组使用)cahrAt(0)表示获取字符串的第一个字符toUpperCase:将字符串全部转换成大写toLowerCase:将字符串全部转换成小写concat:拼接字符串(拼接字符串也可以使用加号来替代)javaString str = "jlc"; str = str.concat("年龄25"); System.out.println(str); // jlc年龄25replace:替换字符串中的字符javaString str = "jlc年龄25"; // 将字符串中所有的jlc字符串替换为jinLinC字符串 System.out.println(str.replace("jlc", "jinLinC")); // jinLinC年龄25 // str.replace() 返回的是执行完替换过的结果,本身的str字符串是没有任何影响的(即str字符串不改变)split:通过指定的字符来分割字符串,对于某些分割字符,我们需要使用转义字符javaString poem = "abc ABC def DEF"; String[] split = poem.split(" "); // 以空格进行分割字符串,返回的是一个数组 for(int i = 0; i < split.length; i++) { System.out.println(split[i]); } // 分割时,有特殊字符,需要加入转义字符 String load = "D:\\aaa\\bbb"; String[] load1 = poem.split("\\\\"); // 根据\\进行分割,要使用到转义字符两个斜杠表示一个斜杠compareTo:比较两个字符串的大小(该方法继承于接口Comparable)javaString a = "jchn"; String b = "jack"; // 先比较长度,如果长度一样(长度不一样返回长度相减后的值),在比较第一个字符,依次类推 System.out.println(a.compareTo(b)); // 2 'c' - 'a' = 2 正数表示前面的字符大,反之,后面大 // 如果比较的两个字符串完全相等,则返回0toCharArry:将字符串转化为字符数组javaString str = "hello"; char[] ch = str.toCharArry(); for(int i = 0; i < ch; i++) { System.out.println(ch[i]); }format:格式字符串javaString str = String.format("我的姓名是%s 年龄是%d 成绩是%.2f", name, age, score);其中
%d等称为占位符,用后续的变量进行填充%s表示后面由字符串进行替换%d表示后面由整数进行替换%.2f表示使用小数进行替换,替换后保留小数点后两位(进行了四舍五入的操作)%c表示使用char字符类型进行替换
StringBuffer类
String类是保存字符串常量的,每次更新都需要重新开辟空间,效率较低,因此java设计者还提供了StringBuilder和StringBuffer来增强String的功能,提高了效率
java.lang.StringBuffer表示可变的字符序列,可以对字符串内容进行增删,其许多方法与String类中的方法相同,但StringBuffer是可变长度的,简而言之,StringBuffer是一个容器
StringBuffer类的继承关系:

StringBuffer的直接父类是AbstractStringBuilder,在父类AbstractStringBuilder中,有属性char[] value,该value数组来存放字符串内容,但是这个数组不是final类型,该数组存放在堆中,而不是像字符串的value存放在常量池中同时
StringBuffer实现了Serializable,即StringBuffer的对象可以串行化(对象可以网络传输和保存到文件)
StringBuffer类是一个final类,不能被继承
String类与StringBuffer类的区别:
String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率低(值放在常量池中)StringBuffer保存的是字符串变量,里面的值可以更改,每次StringBuffer的更新可以更新内容,一般不会更新地址,即创建新对象(只有当原先的地址空间不够了,会统一的扩充一次,将原先的内容拷贝过来),效率高(值放在堆中)
构造器
StringBuffer():构造一个其中不带字符的字符串缓冲区,其初始容量为16个字符,用于存放字符内容StringBuffer(CharSequence seq):构造一个字符串缓冲区,它包含与指定的CharSequence相同的字符StringBuffer(int capacity):构造一个不带字符,但具有指定初始容量的字符串缓冲区,即对char[]的的大小进行指定StringBuffer(String str):构造一个字符串缓冲区,并将内容初始化为指定的字符串内容,容量为当前字符串的长度再加上16个字符
String和StringBuffer的互相转换
在开发中,我们经常将String和StringBuffer进行转换
String转StringBufferjavaString s = "hello"; // 方式一 StringBuffer b1 = new StringBuffer(s); // 返回的b1是StringBuffer对象,s还是String对象 // 方式二 先开辟空间,再进行内容的追加 StringBuffer b2 = new StringBuffer(); b2.append(s);StringBuffer转Stringjava// 方式一 String s1 = b1.toString(); // 方式二 String s2 = new String(b1);
常用方法
StringBuffer类的常用方法有:
append:增javaStringBuffer s = new StringBuffer("hello"); System.out.println(s.append('.')); // hello. 结果返回的还是StringBuffer类型delect(start, end):删,删除索引大于等于start,小于end处的字符replace(start, end, string):将start到end间的内容用string替换掉,不含endindexOf:查找子串在字符第一次出现的索引,如果找不到返回-1insert:插入,在指定的位置直接插入字符串javaStringBuffer s = new StringBuffer("hello"); s.insert(2, "abc"); // 在索引为2的位置插入abc字符串,原来索引为2的内容往后移动 System.out.println(s); // heabcllolength:获取长度
经典案例:
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str); // 根据源码,底层调用的是AbstractStringBuffer的appendNull方法,将null转换为null字符串
System.out.println(sb.length()); // 4
System.out.println(sb); // null
StringBuffer sb1 = new StringBuffer(str); // 查看底层源码,该构造器 super(str.length() + 16)
// 因此这里会出现空指针异常格式化输出小案例:
// 商品的价格,要求输出的形式为:23,123,456.59 要求价格的小数点前面每三位用逗号隔开,在输出
// 思路分析:
// 2. 将String转成StringBuffer,使用StringBuffer的insert方法插入逗号
// 3. 使用相关方法进行字符串的处理
String price = "23123456.59";
StringBuffer sb = new StringBuffer(price);
// 找到小数点的索引,然后在该位置的前三位插入逗号即可
for(int i = sb.lastIndexOf(".") - 3; i > 0; i -= 3) {
sb = sb.insert(i, ","); // 插入逗号
}
System.out.println(sb); // 23,123,456.59StringBuilder类
StringBuilder类是一个可变的字符序列,此类提供一个与StringBuffer兼容的API(大多数的方法是一样的,可以参考StringBuffer类),但不保证同步(StringBuilder不是线程安全的)。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,单线程的时候建议优先采用该类,因为在大多数实现中,它比StringBuffer要快
StringBuilder上的主要操作是append和insert方法,可以重载这些方法,以接收任意类型的数据
继承关系:

StringBuilder类是final类,不能被继承
StringBuilder对象的字符序列仍然存放在其父类AbstractStringBuilder的char[] value;中,因此,字符序列是存放在堆中的
StringBuilder的方法,没有做互斥的处理,即没有synchronized关键字,因此,只推荐在单线程的情况下使用
三大类的比较
StringBuilder和StringBuffer类非常相似,均代表可变字符序列,而且方法也一样String:不可变字符序列,效率低,但是复用率高(可以有很多对象指向常量池中的同一个常量)StringBuffer:可变字符序列,效率较高(增删),线程安全(有synchronized关键字,当一个线程在操作的时候,其他线程就不能操作了)StringBuilder:可变字符序列,效率最高,线程不安全String使用的注意事项说明:javaString s = "a"; // 创建了一个字符串 s += "b"; // 实际上原来的"a"字符串对象已经丢弃了,现在又产生了一个字符串"ab",如果多次执行这些改变字符串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能,因此,如果我们对String做大量修改,不要使用String类型结论:如果我们对
String做大量修改,不要使用String类型,应该使用StringBuffer类
三大类的使用原则
三大类的使用原则非常重要,一定要记下来
- 如果字符串存在大量的修改操作,一般使用
StringBuilder或StringBuffer类 - 如果字符串存在大量的修改操作,并且在单线程的情况,使用
StringBuilder类 - 如果字符串存在大量的修改操作,并且在多线程的情况,使用
StringBuffer类 - 如果我们的字符串很少修改,被多个对象引用,使用
String类,如配置信息等
字符串练习题
将字符串中指定部分进行翻转:如将
abcdef中的bcde翻转为aedcbfjavapublic class StringHomeWork { public static void main(String[] args) { String str = "abcdef"; try { str = reverse(str, 1, 4); } catch (Exception e) { System.out.println(e.getMessage()); } } public static String reverse(String str, int start, int end) { // 对输入的参数做一个验证,思路:写出正确的情况,然后取反 if(!(str != null && start >= 0 && and > start && end < str.length())) { throw new RuntimeException("参数不正确"); } // 思路:先将String转成char[],因为char[]的元素是可以交换的 char[] chars = str.toCharArray(); char temp = ' '; for(int i = start, j = end; i < j; i++, j--) { temp = chars[i]; chars[i] = chars[j]; chars[j] = temp; } // 使用chars重新构建一个字符串返回 return new String(chars); } }
Math类
Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数,这些方法在Math类中一般都是静态static方法,常用的方法有:
abs:取绝对值javaint abs = Math.abs(-9); System.out.println(abs); // 9pow:求幂javaint pow = Math.pow(2, 4); // 2的4次方 System.out.println(abs); // 16ceil:向上取整(返回大于等于该参数的最小整数)javadouble ceil = Math.ceil(3.9); System.out.println(ceil); // 4.0floor:向下取整(返回小于等于该参数的最大整数)javadouble floor = Math.floor(4.001); System.out.println(floor); // 4.0round:四舍五入javalong round = Math.round(-5.001); System.out.println(round); // -5sqrt:开方(根号2),如果被开方的数是负数,则结果返回NaNrandom:取随机数(返回的是0到1之间的随机小数,0可以取到,1取不到)java// 编写一个[a, b]之间的随机整数 System.out.println((int)(a + Math.random() * (b - a + 1)));max:求两个数的最大值javaSystem.out.println(Math.max(1, 9)); // 9min:求两个数的最小值
Arrays类
Arrays类里面包含了一系列的静态方法,用于管理或操作数组(比如排序和搜索)
常见的方法有:
toString:返回数组的字符串形式(用中括号[]包裹)将数组中的内容拼接到一个字符串中javaInteger[] integers = {1, 20, 90}; // 之前的输出方式是通过for循环进行输出,现在可以使用Arrays类中的toString方法,以字符串的方式进行输出 System.out.println(Arrays.toString(integers)); // [1, 20, 90]toString底层的方法也是进行一个for循环,只是在前后都追加一个中括号sort:排序(自然排序和定制排序)排序可以使用冒泡排序,也可以使用Arrays提供的排序方法(这样更加简单)javaInteger arr[] = {1, -1, 7, 0, 89}; // 因为数组是引用类型,所有通过sort排序后,会直接影响到实参arr // 自然排序 Arrays.sort(arr); // 默认是从小到大进行排序的 // 定制排序 // 可以重载sort,可以通过传入一个接口Comparator实现定制排序(比较器,是从大到小排序还是从小到大排序) // 调用定制排序时,第一个参数是排序的数组;第二个参数是实现了Comparator接口的匿名内部类,要求实现compare()方法,这里体现了接口编程的方式 Arrays.sort(arr, new Comparator() { // 使用了匿名内部类的概念 @Override public int compare(Object o1, Object o2) { // 将传入的参数进行向下转型 Integer i1 = (Integer) o1; Integer i2 = (Integer) o2; // i2 - i1 实现了从大到小的排序; 如果改为i1 - i2就是默认排序,即从小到大的排序 return i2 - i1; } }); // 体现了接口编码+动态绑定机制+匿名内部类的综合使用在
binarySort方法底层,会通过匿名内部类的compare方法来决定排序的顺序javawhile (left < right) { int mid = (left + right) >>> 1; if (c.compare(pivot, a[mid]) < 0) right = mid; // 小于0,从小到大排序 else left = mid + 1; // 大于0,从大到小排序 } assert left == right;binarySearch:通过二分搜索法进行查找,要求必须是排序好的javaInteger[] arr = {1, 2, 90, 123, 300}; // 已经排序好的数组 // 查找数组中是否有2这个元素值,返回的是对应元素的索引 int index = Arrays.binarySearch(arr, 2); // 如果查找的元素不存在,则返回-(low + 1)应该存在的位置加1,前面再加一个负号 // 总之,如果返回的是负值,就表示没有找到copyOf:数组元素的复制java// 从数组中arr拷贝arr.length个元素到新数组newArr中 Integer[] newArr = Arrays.copyOf(arr, arr.length); // 这个拷贝的数组长度是可以进行变化的 // arr.length - 1,就是少拷贝一个元素到新数组中,将原数组的最后一个不进行拷贝 // arr.length + 1,多拷贝一个元素到新数组中,但是原数组又没有多余的元素了,就给新数组加null // 如果拷贝的长度小于0,就会抛出异常fill:数组元素的填充javaInteger[] num = new Integer[]{9, 3, 2}; // 用99去填充num数组中的所有数,即用99将数组中的元素值全部进行替换 Arrays.fill(num, 99); // 填充后数组的元素值全部变成了99 {99, 99, 99}equals:比较两个数组元素内容是否完全一致javaInteger[] arr1 = {1, 2, 90, 123, 300}; Integer[] arr2 = {1, 2, 90, 123, 300}; boolean equals = Arrays.equals(arr1, arr2); // trueasList:将一组值,转换成listjava// 将(2, 3, 4)数据转成一个List集合 List asList = Arrays.asList(2, 3, 4); // asList的编译类型是List(接口) 运行类型是java.util.Arrays#ArrayList(Arrays类中的静态内部类)
System类
System类常见的方法:
exit:退出当前程序javaSystem.out.println("ok1"); System.exit(0); // 退出程序 0表示正常退出 System.out.println("ok2"); // 不会执行arraycopy:复制数组元素,使用Arrays.copyOf完成复制数组的底层就是System.arraycopy()javaint[] src = {1, 2, 3}; int[] dest = new int[3]; // dest数组当前为 {0, 0, 0} System.arraycopy(src, 0, dest, 0, 3); // {1, 2, 3} // 其中src表示源数组(待拷贝的数组,提供数据),0表示从源数组中的哪个索引位置开始拷贝 // dest表示目标数组(数组拷贝到哪个数组中),0表示拷贝到目标数组的哪个索引(哪个索引开始拷贝),3表示从源数组拷贝多少个数据到目标数组(一般写成src.length) System.arraycopy(src, 0, dest, 1, 2); // {0, 1, 2}currentTimeMillens:返回当前时间距离1970-1-1的毫秒数javaSystem.out.println(System.currentTimeMillens());gc:运行垃圾回收机制
大数据类
BigInteger类和BigDecimal类
BigInteger和BigDecimal两个类通常用于大数据的处理方案,应用场景:
BigInteger适合保存比较大的整型当我们编程中,需要处理很大的整数,这个时候可能
long就不够用了,我们可以使用BigInteger类来处理javaBigInteger bigInteger = new BigInteger("2322432645467845654654646535654656"); System.out.println(bigInteger); // 2322432645467845654654646535654656 BigInteger bigInteger2 = new BigInteger("23"); // 在对BigInteger进行加减乘除的时候,需要使用对应的方法,不能使用传统的+-*/ // 加add() System.out.println(bigInteger.add(bigInteger2)); // 减subtract() System.out.println(bigInteger.subtract(bigInteger2)); // 乘multiply() System.out.println(bigInteger.multiply(bigInteger2)); // 除divide() 这里的除是指整除 System.out.println(bigInteger.divide(bigInteger2));BigDecimal适合保存精度更高的浮点型(小数)在编程中,对于小数,如果位数特别大,
double往往不够用,系统会进行精度的缩减,如果我们不希望精度的缩减,我们可以使用BigDecimal类保存精度更高的小数javaBigDecimal bigDecimal = new BigDecimal("232243.2645467845654654646535654656");其加减乘除的运算和
BigInteger类似,但是使用除法时,可能会出现除不尽的问题(会出现无限循环,从而抛出异常)如果我们不想让其抛出异常,我们只需要给定精度即可java// 如果有无限循环的小数,指定了BigDecimal.ROUND_CEILING精度,就会保留到分子的精度,不会再抛异常 System.out.println(bigDecimal.divide(bigDecimal2, BigDecimal.ROUND_CEILING));
日期类
在编程过程中一般会涉及到日期,Java中有三种日期类,分别称为第一代、第二代和第三代
第一代日期类Date
第一代日期类Date是最早出现的日期类,可以精确到毫秒,代表特定的瞬间
与Date类配套使用的有SimpleDateFormat:用于格式和解析日期的具体类,允许进行格式化(日期-->文本)、解析(文件-->日期)和规范化
Date类的继承关系:

第一代日期类Date目前有些方法已经过时了,使用的时候需要注意
在IDEA代码编译器的类图中,是可以展示类的属性,展示的属性不单单局限于我们声明的具体属性,对于getXxx和setXxx方法中的xxx内容,查看属性时,也会被放到类图中的属性中,当作该类的属性
基本使用
使用之前需要引入时间相关的包:import java.util.Date;
import java.util.Date;
public class Date01 {
public static void main(String[] args) throws ParseException {
// 获取当前的系统时间
Date d1 = new Date(); // Thu Mar 04 17:19:30 CST 2025
// 我们需要对日期的格式进行转换,可以指定我们需要的时间形式,注意,这里使用的字母是规定好的
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss E");
String format = sdf.format(d1); // 2025年03月04日 05:19:30 星期二
// 通过指定的毫秒数来获取时间
Date d2 = new Date(9234567); // Thu Jan 01 10:33:54 CST 1970
// 将一个格式化的字符串转换成对应的Date
String s = "2025年03月04日 05:19:30 星期二";
// 这里需要抛出异常,防止报错,这里使用的sdf格式需要和给定的字符串格式一样,否会抛出转换异常
Date parse = sdf.parse(s); // Thu Mar 04 17:19:30 CST 2025
}
}格式化时间的内容的特定字母常用的有:
y:年;M:月;w:年中的周数;W:月份中的周数;D:年中的天数;d:月份中的天数;F:月份中的星期;E:星期中的天数;a:am/pm标记;H:一天中的小时数(0-23);k:一天中的小时数(1-24);K:am/pm中的小时数(0-11);h:am/pm中的小时数(0-12);m:小时中的分钟数;s:分钟中的秒数;S:毫秒数;
第二代日期类Calendar
第二代日期类Calendar类(日历),Calendar类是一个抽象类,它为特定瞬间与一组如YEAR、MONTH、DAY_OF_MONTH和HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法
Calendar类的继承关系:

Calendar类是一个抽象类,其构造器是私有的,我们要获取Calendar类的实例,需要使用该类提供的getInstance()方法
基本使用
使用之前需要引入时间相关的包:import java.util.Calendar;
import java.util.Calendar;
public class Calendar01 {
public static void main(String[] args) {
// 获取一个容日历类的对象,不能使用new方法,因为构造器是私有的
Calendar c = Calendar.getInstance(); // c输出的内容,将时间信息藏在了相应的字段中
// 获取日历对象的某个日历字段
c.get(Calendar.YEAR); // 获取当前时间的年
c.get(Calendar.MONTH) + 1; // 获取当前时间的月,注意要加一,因为是按照0开始编号的
c.get(Calendar.DAY_OF_MONTH); // 获取当前时间的日
// 如果要通过24小时的进制来获取时间,使用HOUR_OF_DAY
c.get(Calendar.HOUR); // 获取当前时间的小时
c.get(Calendar.MINUTE); // 获取当前时间的分钟
c.get(Calendar.SECOND); // 获取当前时间的秒
// Calendar类没有提供对应的格式化的类,需要自己进行拼接组合,可以更加灵活化
System.out.println(c.get(Calendar.YEAR)+"年" + (c.get(Calendar.MONTH) + 1)+"月");
}
}第三代日期类
对于第一代日期类,在jdk1.0就有了,但是它的大多数方法已经在jdk1.1时引入了Calender类之后就被弃用了,然而,Calender也存在一些问题:
- 可变性问题:像日期和时间这样的类应该是不可变的,但是
Calender类型是可变的 - 偏移性:
Date中的年份是从1900年开始的,而月份都是从0月开始的 - 格式化:格式化只对
Date有用,Calendar不能使用格式化 - 此外,第一代和第二代时间类的线程都不是安全的,不能处理闰秒等(每隔两天,多出1秒)
针对于上述的情况,Java设计者在jdk8.0之后,引入了三个日期类:
LocalDate:日期类,返回年月日LocalTime:时间类,返回时分秒LocalDateTime:日期时间类。返回年月日和时分秒,用这个即可
第三代日期的格式日期类DateTimeFormatter,类似于第一代日期类中的格式日期类SimpleDateFormat
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(格式);
String str = dtf.format(日期对象);时间戳Instant:类似于Date,提供了一系列和Date类转换的方式:
Instant--->Date:Date date = Date.from(instant);Date--->Instant:Instant instant = date.toInstant();
// 通过静态方法now() 获取表示当前时间戳的对象
Instant instant = Instant.now(); // 2021-03-04T10:37:19.564Z
// 通过from可以把Instant对象转成Date对象
Date date = Date.from(instant);
// 通过Date的toInstant() 又可以将Date对象重新转换成Instant对象
Instant instant = date.toInstant();基本使用
import java.util.Calendar;
public class DateTime {
public static void main(String[] args) {
// 第三代日期
// 使用now返回当前日期时间的对象
LocalDateTime ldt = LocalDateTime.new(); // 2025-04-18T18:56:12.082
ldt.getYear(); // 获取年
ldt.getMonthValue(); // 获取月。返回的是数字,如3
ldt.getMonth(); // 获取月,返回的是英文的月份,如MARCH
ldt.getDayOfMonth(); // 获取日
ldt.getHour(); // 获取时
ldt.getMinute(); // 获取分
ldt.getSecond(); // 获取秒
// 使用DateTimeFormatter对象来进行格式化
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
String str = dtf.format(ldt); // 2025年04月18日 18时56分12秒
}
}第三代日期类还有许多的方法:(其他方法查看API手册)
提供了
plus和minus方法,可以对当前时间进行加或减javaLocalDateTime ldt = LocalDateTime.new(); // 获取当前时刻的年月日时分秒 // 900天之后的年月日时分秒 LocalDateTime localDateTime = ldt.plusDays(900); // plusDays表示加天,也可以加年等 // 300分钟前的年月日时分秒 LocalDateTime localDateTime2 = ldt.minusMinutes(300);
