常用类
常用类是比较重要的,在面试的时候也是问的比较多的
包装类
针对八种基本的数据类型,定义了相应的引用类型,这些基本数据的引用类型叫做包装类
这些基本的数据类型,有了类的特点,就可以调用类中的方法
基本数据类型 | 包装类 |
---|---|
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)); // false
equalsIgnoreCase
:判断内容是否相等(不区分大小写)length
:获取字符串长度(获取字符的个数)javaString str = "Hello"; System.out.println(str.length()); // 5
indexOf
:获取某个字符在字符串中第一次出现的索引,索引从0开始,如果找不到,返回-1javaString str = "jlc@sdfds@efs"; int index = str.indexOf('@'); System.out.println(index); // 3 // 该方法除了是单个字符,还可以是字符串 System.out.println(str.indexOf("lc")); // 1
lastIndexOf
:获取某个字符在字符串中最后一次出现的索引,索引从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年龄25
replace
:替换字符串中的字符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 正数表示前面的字符大,反之,后面大 // 如果比较的两个字符串完全相等,则返回0
toCharArry
:将字符串转化为字符数组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
转StringBuffer
javaString s = "hello"; // 方式一 StringBuffer b1 = new StringBuffer(s); // 返回的b1是StringBuffer对象,s还是String对象 // 方式二 先开辟空间,再进行内容的追加 StringBuffer b2 = new StringBuffer(); b2.append(s);
StringBuffer
转String
java// 方式一 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
替换掉,不含end
indexOf
:查找子串在字符第一次出现的索引,如果找不到返回-1insert
:插入,在指定的位置直接插入字符串javaStringBuffer s = new StringBuffer("hello"); s.insert(2, "abc"); // 在索引为2的位置插入abc字符串,原来索引为2的内容往后移动 System.out.println(s); // heabcllo
length
:获取长度
经典案例:
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.59
StringBuilder
类
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
翻转为aedcbf
javapublic 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); // 9
pow
:求幂javaint pow = Math.pow(2, 4); // 2的4次方 System.out.println(abs); // 16
ceil
:向上取整(返回大于等于该参数的最小整数)javadouble ceil = Math.ceil(3.9); System.out.println(ceil); // 4.0
floor
:向下取整(返回小于等于该参数的最大整数)javadouble floor = Math.floor(4.001); System.out.println(floor); // 4.0
round
:四舍五入javalong round = Math.round(-5.001); System.out.println(round); // -5
sqrt
:开方(根号2),如果被开方的数是负数,则结果返回NaN
random
:取随机数(返回的是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)); // 9
min
:求两个数的最小值
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); // true
asList
:将一组值,转换成list
java// 将(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);