前言
这一篇讲API,有很多很多的API
1. Object
它是所有类的祖宗类,所以任何类都可以直接使用Object的一些方法
1.1 toString
从这个我们就可以看出,平时对s1的打印其实是默认调用了它的toString函数,因为toString是灰色的
但是默认打出来的是地址,这也是为什么我们会认为名字就是地址,其实就是地址
要想打印出真正的内容,就必须在Student类中把toString函数重写
这也是为什么String打出来的不是地址,因为重写了
public class Student {
private int age;
private String name;
public Student(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public Student() {
}
}
System.out.println(s1);
System.out.println(s1.toString());
1.2 equals
System.out.println(s1.equals(s2));
正常的equals就是比较的地址,重写之后,比的就是里面的内容了
System.out.println(s1==s2);
没有重写的话,就和上面这个是一样的效果
我们用系统的快捷方式来重写
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
getClass() != o.getClass()这个主要是判断类型的,看两个的类型相不相同
getClass() 会返回一个Student.class
至于Objects,这也是一个类,后面再说
1.3 clone
clone会克隆一个一模一样的对象,然后返回,但是克隆的只是浅克隆,对于里面的自定义对象,只会克隆地址,不会克隆里面的数据
但是注意一下,克隆是被保护的,所以要重写一下,才可以正常调用
public Object clone() throws CloneNotSupportedException {
Object clone = super.clone();
return clone;
}
throws CloneNotSupportedException这个是抛异常,暂时不讲
****在idea中我们有错误,点上去显示错误,然后ALT+回车就可以修正错误
Student s3= (Student) s1.clone();
这样就可以克隆,因为返回的是Object,所以要强转一下
Student s1=new Student(12,"111111");
Student s3= (Student) s1.clone();
System.out.println(s3.getName());
System.out.println(s3.getAge());
System.out.println(s1.getName());
System.out.println(s1.getAge());
深克隆就是面对里面的自定义类型(除了String),不是拷贝地址,而是自己开辟来拷贝,String这个自定义就是直接拷贝地址就可以了,因为它存的内容在静态区,不可改变
如果里面都是普通类型,那么就不会存在深浅拷贝的问题
2.Objects
Objects调用的直接就是静态方法,但方法都和Object差不多
2.1 equals
String s1="aaaaa";
String s2="aaaaa";
System.out.println(s1.equals(s2));
System.out.println(Objects.equals(s1, s2));
这就是两个的区别,都是比的地址,因为String是存在静态区的,所以String的内容一样,地址就一样
这个s1.equals(s2)的坏处就是,万一s1为null,那么就会出错了
而Objects.equals(s1, s2)是直接返回false,不会出错
2.2 isNull
String s1="aaaaa";
String s2=null;
System.out.println(Objects.isNull(s1));
System.out.println(Objects.isNull(s2));
这个函数的作用就是看是否为null,如果是的话就直接返回true
等价于这个
System.out.println(s2==null);
2.3 nonNull
String s1="aaaaa";
String s2=null;
System.out.println(Objects.nonNull(s1));
System.out.println(Objects.nonNull(s2));
这个就是不是null返回true
3. 包装类
这个就是把基本的数据类型包装成对象的类
因为万物皆对象,所以也需要把基本数据类型包装成类
除了int和char,其余的基本数据类型的包装类的名字就是首字母大写
int是Integer,char是Character
这里我们以int为例
它有构造函数,但是它的构造函数已经过时了,不能用了
我们一般用calueOf来构造
这是个静态方法
Integer i=Integer.valueOf(1);
valueOf这个方法,会返回一个Integer的类对象
System.out.println(i);
对这个对象的打印就是打印int这个数值
下面我们来讲一下自动装箱
Integer a1=10;
可以把基本数据类型自动转化为对象,这个过程就叫做自动装箱
int a2=a1;
把包装类型的对象转换成对应的基本数据类型,这个就叫做自动拆箱
又因为泛型和集合不支持基本数据类型,只能用引用数据类型,但是我们放入Integer就可以插入intl了
3.1 toString
String a3=a1.toString();
System.out.println(a3 + 1);
这个方法的作用主要就是将里面的基本数据转换为字符串
所以得到的结果就是101而不是11
3.2 parseInt
String a4="1234";
int age=Integer.parseInt(a4);
System.out.println(age + 1);
这个函数的主要作用就是将字符串转换为基本数据类型,注意Integer的parseInt就只能将字符串转换为int,所以字符串为double类型时就会报错
这时就要用Double的parseDouble了
4. StringBuilder
这个也是装字符串的,只不过这个装的字符串是可变的,不像String,由于String不可变,每次都要重新找一个新的字符串,所以效率String的要低一点
4.1 构造器
StringBuilder s3=new StringBuilder();
StringBuilder s4=new StringBuilder("aaaa");
4.2 append
这个方法的主要作用就是拼接
StringBuilder s3=new StringBuilder();
s3.append(12);
s3.append("aaa");
s3.append(true);
System.out.println(s3);
这个拼接不管你传入的参数是什么类型,结果最终都是会转成字符串来拼接的
由于append返回的还是StringBuilder,所以我们可以链式编程
StringBuilder s4=new StringBuilder("aaaa");
s4.append(12).append("int");
System.out.println(s4);
4.3 reverse
s4.reverse();
System.out.println(s4);
这个就是反转
4.4 toString
String s5=s4.toString();
就是将StringBuilder的内容转换为String
5. StringBuffer
这个和StringBuilder的方法使用是一样的,只不过这个是线程安全的
5.1 练习
设计一个方法,返回整型数组,返回的数组类型为[11, 22, 33]
public static String change(int[] arr){
StringBuffer s=new StringBuffer();
s.append("[");
for(int i=0;i<arr.length;i++){
if(i==arr.length-1){
s.append(arr[i]);
}else{
s.append(arr[i]+", ");
}
}
s.append("]");
return s.toString();
}
System.out.println(change(new int[]{1, 2, 3, 4, 5, 6}));
5-6. StringJoiner
这个方法的主要作用就是优化上面这个方法的
StringJoiner s6=new StringJoiner(", ");
s6.add("12");
s6.add("14");
s6.add("15");
System.out.println(s6);
构造器的作用就是给每个add添加的数据提供一个分隔符,这里的分隔符就是逗号+空格
然后add添加的内容只能是字符串
StringJoiner s6=new StringJoiner(", ","[","]");
s6.add("12");
s6.add("14");
s6.add("15");
System.out.println(s6);
这个构造器后面两个参数的意思就是,串的开始符号是[,结束符号是]
然后这个类也是有toString和length方法的
6. Math
这个数学类就是一个工具类,提供的都是一些静态方法
6.1 abs
这个就是求绝对值
System.out.println(Math.abs(-1234));
6.2 ceil
这个就是向上求整
6.3 floor
向下取整
6.4 round
四舍五入保留整数,返回的是长整型
System.out.println(Math.round(3.49));
6.5 max与min
取俩个数的最大值或者最小值
System.out.println(Math.max(12, 13));
6.6 pow
取次方
System.out.println(Math.pow(2, 3));
这里取的就是2的3次方,其中两个参数可以为浮点数,返回值也可以是浮点数
6.7 random
这个返回的就是一个随机数,在[0,1)
System.out.println(Math.random());
7. System
也是一个工具类
7.1 exit
System.out.println(Math.pow(2, 3));
System.exit(0);
System.out.println(Math.random());
exit是终止程序,参数为0,就是人为的终止程序,它后面的程序就不会执行了,非0的话,就是异常终止程序
一般不使用这个方法
7.2 currentTimeMillis
这个就是获取时间的,返回值是一个long类型的
long time=System.currentTimeMillis();
System.out.println(time);
这个返回的是一个时间戳,只不过是以毫秒为单位的
这个方法的主要作用就是计算用时多久
long time=System.currentTimeMillis();
for(int j=0;j<1000000;j++){
System.out.println(j);
}
long time1=System.currentTimeMillis();
System.out.println("用时"+(time1-time)/1000+'s');
8. Runtime
代表程序的运行环境
是一个单例类
Runtime r=Runtime.getRuntime();
8.1 exit
r.exit(0);
终止程序
8.2 availableProcessors
System.out.println(r.availableProcessors());
这里是获取虚拟机能使用的处理器数
8.3 totalMemory
System.out.println(r.totalMemory());
System.out.println(r.totalMemory()/1024.0+"KB");
System.out.println(r.totalMemory()/1024.0/1024.0+"MB");
这个就是返回虚拟机的内存总量
8.4 freeMemory
System.out.println(r.freeMemory()/1024.0/1024.0+"MB");
这个是返回虚拟机中可用的内存总量
8.5 exec
r.exec("\"C:\\Users\\zjdsx\\Desktop\\贪吃蛇.exe\"");
r.exec("QQ");
这个函数的作用就是启动某个程序,输入路径就可以了
因为QQ我们加入了PATH路径的,所以会默认去环境变量PATH里面去找
但是用这个要抛异常,AIT+回车就可以了
Process p=r.exec("QQ");
Thread.sleep(5000);//单位是毫秒
p.destroy();
我们可以定义一个Process变量,来接收我们打开的QQ,然后destroy就是关闭
9. BigDecimal
这个是用来解决浮点数计算,结果失真的问题的
System.out.println(0.1 + 0.2);
为什么会这样呢,因为某些浮点数无法用二进制精确表示,只能无限接近,所以会有这种失真问题
9.1 构造器
注意不推荐使用第一个构造器,因为第一个的话,没什么区别,还是会失真,它只是把浮点数存在里面了而已
BigDecimal a1=new BigDecimal(Double.toString(0.2));
BigDecimal b1=new BigDecimal(Double.toString(0.1));
这样就可以了,里面存的是字符串了
9.2 valueOf
BigDecimal a1=BigDecimal.valueOf(0.2);
BigDecimal b1=BigDecimal.valueOf(0.1);
或者这样也可以
9.3 add
BigDecimal c1=a1.add(b1);
System.out.println(c1);
9.4 divide
BigDecimal a1=BigDecimal.valueOf(0.2);
BigDecimal b1=BigDecimal.valueOf(0.1);
BigDecimal c1=b1.divide(a1);
System.out.println(c1);
除法
BigDecimal a1=BigDecimal.valueOf(0.3);
BigDecimal b1=BigDecimal.valueOf(0.1);
BigDecimal c1=b1.divide(a1);
System.out.println(c1);
但是这个除法就不行了,因为0.1/0.3是无限循环小数
BigDecimal a1=BigDecimal.valueOf(0.3);
BigDecimal b1=BigDecimal.valueOf(0.1);
BigDecimal c1=b1.divide(a1,2, RoundingMode.HALF_UP);
System.out.println(c1);
这样写就可以了
表示保留两位小数
9.5 subtract
BigDecimal c1=b1.subtract(a1);
System.out.println(c1);
9.6 multiply
BigDecimal c1=b1.multiply(a1);
System.out.println(c1);
这个就是当做的字符串来计算,小数点对齐来算的
9.7 doubleValue
BigDecimal a1=BigDecimal.valueOf(0.3);
BigDecimal b1=BigDecimal.valueOf(0.1);
double rs=a1.doubleValue();
System.out.println(rs);
这个就是把BigDecimal转化为double
10.Date
10.1 构造器
Date d=new Date();
System.out.println(d);
这样的构造器就是默认以当前时间为准的,存的就是当前的时间
10.2 getTime
Date d=new Date();
System.out.println(d);
System.out.println(d.getTime());
这个getTime获得的就是时间戳,单位为毫秒值
10.3 构造器2
Date d=new Date();
System.out.println(d);
long time=d.getTime();
time+=10000;
Date d1=new Date(time);
System.out.println(d1);
这个构造器就是以我们传入的时间戳来设置时间
10.4 setTime
Date d=new Date();
System.out.println(d);
long time=d.getTime();
time+=10000;
Date d1=new Date(time);
System.out.println(d1);
Date d2=new Date();
d2.setTime(time);
System.out.println(d2);
这个setTime就是用来更改时间的,用时间戳来更改
11. LocalDate,LocalTime,LocalDateTime
上面我们讲的Runtime,BigDecimal,Date都是JDK8之前的时间API
不太好,
还有没讲的Calendar,格式化器,都可以不学的,因为都老了
第一,很多方法被淘汰了
第二,可变的对象,修改后里面的内容就变了
第三,线程不安全的
第四只能精确到毫秒
后面我们讲的这些时间API都是新的,不可变对象,线程安全,能精确到纳秒的
LocalDate(年月日星期)
LocalTime(时分秒纳秒)
LocalDateTime(年月日星期时分秒纳秒)
11.1 LocalDate
LocalDate ld=LocalDate.now();
System.out.println(ld);
通过静态方法now就可以了
获取数据
int year=ld.getYear();//年
int month=ld.getMonthValue();//月
int day=ld.getDayOfMonth();//日
int dayOfYear=ld.getDayOfYear();//一年中的第几天
int dayOfWeek=ld.getDayOfWeek().getValue();//星期几
//直接修改某个信息,修改完之后,会返回一个新的对象,原来的对象不改变
LocalDate ld2=ld.withYear(2099);
//withMonth,withDayOfMonth,withDayOfYear
System.out.println(ld2);
LocalDate ld3=ld.plusDays(2);//加上一些东西,并返回
LocalDate ld4=ld.minusDays(2);//减上一些东西,并返回
LocalDate ld5=LocalDate.of(2022,2,2);
System.out.println(ld5);//获取指定的对象
System.out.println(ld3.equals(ld4));
System.out.println(ld3.isAfter(ld4));//ld3日期是否在ld4后面
System.out.println(ld3.isBefore(ld4));
11.2 LocalTime
然后就是LocalTime的使用和LocalDate几乎是一模一样的,getHour,getMinute等等,还有就是这个可以存到纳秒
11.3 LocalDateTime
LocalDateTime就是前面两个的合体,也是差不多的,get,with,isafter
讲一个稍微不同的,就是LocalDateTime可以转换为其他两个,其他两个又可以转化回来
LocalDateTime ldt=LocalDateTime.now();
LocalDate ld=ldt.toLocalDate();
LocalTime lt=ldt.toLocalTime();
LocalDateTime ldt1=LocalDateTime.of(ld,lt);
11.4 时区时间
ZoneId代表一个时区的id
ZoneId zoneId=ZoneId.systemDefault();//获取我们这个系统的默认时间
System.out.println(zoneId.getId());//获取id
System.out.println(zoneId);
因为我们与伦敦相差八个小时,所以就是这样,这就是北京时间
System.out.println(ZoneId.getAvailableZoneIds());//获取Java所支持的全部时区
ZoneId zoneId1=ZoneId.of("America/New_York");//这个是把某个时区分装成ZoneId
ZoneId zoneId1=ZoneId.of("America/New_York");//这个是把某个时区分装成ZoneId
ZonedDateTime now=ZonedDateTime.now(zoneId1);//这个是把时区时间分装成相应的时间对象
System.out.println(now);
可以看出,这个时候,纽约才8点
ZonedDateTime now1=ZonedDateTime.now(Clock.systemUTC());//这个是获取伦敦的,也就是经度线0的
System.out.println(now1);
ZonedDateTime now2=ZonedDateTime.now();
System.out.println(now2);//这个是获取当前时区的时间的
然后这个时区时间也可以调用get,with那些方法
还有就是其实原来的Calendar也是可以得到时区的
11.5 时间戳
获得时间戳精确到纳秒
就是总秒数加上不足1秒的纳秒数
Instant now=Instant.now();//存储的就是总秒数加纳秒
long second=now.getEpochSecond();//获得总秒数
System.out.println(second);
int nano=now.getNano();//纳秒数
System.out.println(nano);
Instant now=Instant.now();//存储的就是总秒数加纳秒
long second=now.getEpochSecond();//获得总秒数
System.out.println(second);
int nano=now.getNano();//纳秒数
System.out.println(nano);
System.out.println(now);
后面从小数点开始的就是纳秒数,前面的都是总秒数
Instant instant=now.plusNanos(111);
加上纳秒并返回
Instant instant1=Instant.now();
//代码
Instant instant2=Instant.now();
这个类的主要作用就是记录自己的函数执行了好久
11.6 格式化器
JDK8之前也有格式化器,但那个是线程不安全的,我们用这个更安全
DateTimeFormatter formatter=DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");//格式化器对象
//后面的时间就用这个来格式化了
LocalDateTime now=LocalDateTime.now();
System.out.println(now);
String rs=formatter.format(now);
System.out.println(rs);
注意除了字母,其他的都可以随便变,因为字母有特定含义,比如y表示年,四个y就表示年是四位数
然后就是格式化时间还有其他方式,就是把格式化器作为参数传进去
String rs2=now.format(formatter);
System.out.println(rs2);
然后就是格式化了时间,我们对应就要解析时间
String date="2024年10月11日 21:09:44";
LocalDateTime ldt=LocalDateTime.parse(date,formatter);//就是把字符串解析成时间对象,前面是将时间格式化为字符串
System.out.println(ldt);
11.7 Period
这个主要是用来计算两个日期相差的天数,月数,年数
LocalDate start=LocalDate.of(2029,8,10);
LocalDate end=LocalDate.of(2029,8,15);
Period period=Period.between(start,end);//这个period对象分装两个日期对象
System.out.println(period.getDays());//获取相差天数
System.out.println(period.getMonths());//获取相差月数
System.out.println(period.getYears());//获取相差年数
11.8 Duration
算两个时间相差的天数,分钟数,纳秒数等
LocalDateTime start=LocalDateTime.of(2025,11,11,11,2,2,2);
LocalDateTime end=LocalDateTime.of(2025,11,11,11,2,5,4);
Duration duration=Duration.between(start,end);
System.out.println(duration.toDays());
System.out.println(duration.toNanos());//纳秒
System.out.println(duration.toSeconds());//相差秒数
12. Arrays
12.1 toString
这个是它的静态方法,可以把数组内容转换成字符串
什么类型的数组都可以转换
int[]arr={1,2,3,4,5,6,7};
System.out.println(Arrays.toString(arr));
12.2copyOfRange
int[]arr2=Arrays.copyOfRange(arr,1,4);
System.out.println(Arrays.toString(arr2));
copyOfRange可以把arr的数组下标1~4(左闭右开)的内容拷贝创建一个新数组,并返回
12.3 copyOf
int[]arr3=Arrays.copyOf(arr,10);
System.out.println(Arrays.toString(arr3));
int[]arr4=Arrays.copyOf(arr,3);
System.out.println(Arrays.toString(arr4));
这也是一个数组的拷贝,后面那个参数是长度,长度不够,用0,长度太短,有多少拷贝多少
12.4 setAll
这个是将原数组的内容修改,并保存,第一个参数就是原数组,第二个参数是你修改的方法,其实也是一个匿名对象
double[]arr5={100,200,300};
Arrays.setAll(arr5, new IntToDoubleFunction() {
@Override
public double applyAsDouble(int value) {
return arr5[value]*0.8;
}
});
System.out.println(Arrays.toString(arr5));
匿名对象中value其实就是下标,他会慢慢变大的
这个就是setAll的实现
12.5 sort
double []arr={99.8,128,100};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
这个的作用就是排序,排的是升序
但我们如果排的是对象呢
public class Student {
private String name;
private double height;
private int age;
public Student(String name, double height, int age) {
this.name = name;
this.height = height;
this.age = age;
}
public Student() {
}
}
Student[]arr=new Student[4];
arr[0]=new Student("aaaa",169.5,23);
arr[1]=new Student("bbbb",163.8,26);
arr[2]=new Student("bbbb",163.8,26);
arr[3]=new Student("cccc",167.5,24);
Arrays.sort(arr);
我们可以看出,直接对对象排序肯定是不行的,所以下面我们来讲两个方法
12.6 实现Comparable接口
public class Student implements Comparable<Student>{
private String name;
private double height;
private int age;
public Student(String name, double height, int age) {
this.name = name;
this.height = height;
this.age = age;
}
public Student() {
}
@Override
public int compareTo(Student o) {
return 0;
}
}
意思就是我们用要比较的类去实现一个Comparable接口,然后重写compareTo,这个方法就是我们的比较规则
然后就是这个Comparable也是一个泛型,类型就是我们要比较的类型
然后compareTo比较的就是this和o
一般有三个约定
左边对象大于右边,返回正整数
左边对象小于右边,返回负整数
左边对象等于右边,返回0
如果严格按照这个要求来,那么返回的就是升序的
如果要实现降序的,把逻辑反过来就可以了,接下来我们讲的都是升序
public class Student implements Comparable<Student>{
private String name;
private double height;
private int age;
public Student(String name, double height, int age) {
this.name = name;
this.height = height;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", height=" + height +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
//按照年龄来排序
if(this.age>o.age){
return 1;
}else if(this.age<o.age){
return -1;
}else {
return 0;
}
}
}
其实上面的逻辑可以更简单点
@Override
public int compareTo(Student o) {
return this.age-o.age;
}
12.7 传入比较器对象
其实sort不止可以传一个参数,它被重载了的,可以传两个参数,第二个参数就是比较器
这个比较器就是Comparator的匿名内部类对象,然后自己定义比较方法
Arrays.sort(arr, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return 0;
}
});
//我们在Student这个类里面增加一些函数
public String getName() {
return name;
}
public double getHeight() {
return height;
}
public int getAge() {
return age;
}
Comparator也是一个泛型,类型就是我们要比较的类型
然后规则就是上面的规则
这里我们比较身高
首先不能这样写
因为返回的是整型
也不能强转,因为0.1这种就被强转为0了
只能自己乖乖的比较
Arrays.sort(arr, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
if(o1.getHeight()>o2.getHeight()){
return 1;
}else if(o1.getHeight()<o2.getHeight()){
return -1;
}else {
return 0;
}
}
});
Arrays.sort(arr, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return Double.compare(o1.getHeight(),o2.getHeight());
}
});
我们也可以这样写
这个方法的实现也是和我们原来写的是一样的
总结
下一节我们继续讲Java的相关知识,从lambda开始讲