API(Application Programming Interface):应用程序编程接口。
简单的来说:就是Java帮我们已经写好的方法,我们可以直接使用。
Object、Objects、StringBuilder、Math、System、BigDecimal等
一个类要么默认继承了Object类,要间接继承了Object类,Object类是Java中的祖宗类。
Object类的方法是一切子类都可以直接使用,所以我们要学习Object类的方法。
方法名 | 说明 |
public String toString() | 默认是返回当前对象在堆内存中的地址信息:类的全限定名@内存地址 |
public Boolean equals(Objecto) | 默认是比较当前对象与另一个的地址是否相同,相同返回true,不相同即返回false |
方法名 | 说明 |
public String toString() | 默认是返回当前对象在堆内存中的地址信息:类的全限定名@内存地址 |
public class Student{ // extends object 任何定义的类都继承祖宗类:Object,写不写都行
// 定义学生属性:姓名性别年龄
private String name;
private char sex;
private int age;
public Student() {
}
public Student(String name, char sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
// @Override
// public boolean equals(Object o) {
// if (this == o) return true;
// if (o == null || getClass() != o.getClass()) return false;
// Student student = (Student) o;
// return sex == student.sex &&
// age == student.age &&
// Objects.equals(name, student.name);
// }
//
// @Override
// public String toString() {
// return "Student{" +
// "name='" + name + '\'' +
// ", sex=" + sex +
// ", age=" + age +
// '}';
// }
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
Student stu1 = new Student("双面龟", '龟', 15);
// toString:默认是返回当前对象在堆内存中的地址中的地址信息——>类的全限名@内存地址
String s = stu1.toString();
System.out.println(s);
System.out.println("------");
// 默认可以省略toString调用不写
System.out.println(stu1.toString());
System.out.println(stu1);
}
}
控制台输出结果:
开发中直接输出对象,默认输出对象地址其实是毫无意义的,开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息。这个时候,父类toString方法存在的意义就是为了被子类重写,以便于返回对象的内容信息,而不是地址信息
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
'}';
}
控制台输出结果:
此时父类Obiect的toString方法已被子类Student重写,按照Java的就近原则,就会找子类的toString。
Object的toString方法的作用是什么?
默认是打印当前对象的地址信息;
让子类重写,以便于返回子类对象的内容信息。
方法名 |
说明 |
public Boolean equals(Object o) | 默认是比较当前对象和另一个对象是否相同,相同返回true,不同返回false |
例:如果是直接使用默认equals比较两个对象:
public class Test02 {
public static void main(String[] args) {
Student stu1 = new Student("阿酷", '鱼', 15);
Student stu2 = new Student("阿酷", '鱼', 15);
System.out.println(stu1==stu2);
}
}
因为stu1和stu2都是新对象,地址不同,比对后返回false:
父类equals方法存在的意义就是为了被子类重写,以便子类自己来指定比较规则这个就是equals存在的意义。
@Override
public boolean equals(Object o) {
// 第一层过滤:判断是否为同一个对象在比较,是则返回true
if (this == o) return true;
/* 第一层过滤后,证明不是自己和自己比较进入第二层
进入第二层过滤:判断传入的’0‘是否是null,如果是空值直接返回false
或者是this.getClass(stu1的类型)是否与o.getClass(stu2的类型)不相同,是则返回false
*/
if (o == null || getClass() != o.getClass()) return false;
// 过滤完毕,说明传入的’o‘不是null,stu1和stu2类型也相同,将Ojbect类型的’o‘强制转换为Student类型
Student student = (Student) o;
// 两者性别、年龄、性别都相等、返回true,不然就是返回false
return sex == student.sex &&
age == student.age &&
Objects.equals(name, student.name);
}
public class Test02 {
public static void main(String[] args) {
Student stu1 = new Student("阿酷", '鱼', 15);
Student stu2 = new Student("阿酷", '鱼', 15);
Student stu3 = new Student("泡泡", '鱼', 15);
System.out.println(stu1==stu2);
System.out.println(stu1.equals(stu1));
System.out.println(stu1.equals(null));
System.out.println(stu1.equals(stu3));
System.out.println(stu1.equals(stu2));
}
}
控制台输出结果:
Object的equals方法的作用是什么?
默认是否与另一个对象比较地址是否相等;
让子类重写,以便于比较2个子类对象的内容是否相等。
Objects类与Object是继承关系,Objects类是从jdk1.7开始之后才有的。
方法名 | 说明 |
public static boolean equals(Object a,Object b) | 比较两个对象,底层会进行非空判断,从而可以避免空指针异常;再进行equals比较 |
public static boolean isNull(Object obj) | 判断变量是否为null,为null返回true,否则返回false |
官方在进行字符串比较时,没有对象自己的equals方法,而是选择了Objects的euqals方法来比较两个对象:
Object的equals方法留下的隐患:
Objects的equals方法比较的结果是一样的,但是更安全。
Objects的equals方法解决了这个隐患:
控制台输出结果:
public class Test04 {
public static void main(String[] args) {
String s1 = null;
String s2 = "嘻嘻";
// 默认方法直接判断
System.out.println(s1 == null);
System.out.println(s2 == null);
// 调用isNull方法的话就显得更专业、优雅
System.out.println(Objects.isNull(s1));
System.out.println(Objects.isNull(s2));
}
}
控制台输出结果:
StringBuilder是一个可变的字符串类,我们可以把它看成是一个对象容器。
作用:提高字符串的操作效率,如拼接、修改等。
构造器名称 | 说明 |
public StringBuilder() | 创建一个空白的可变的字符串对象,不包含任何内容 |
public StringBuilder(String str) | 创建一个指定字符串内容的可变字符串对象 |
方法名称 | 说明 |
public StringBuilder append(任意类型) | 添加数据并返回 |
public StringBuilder reverse() | 将对象的内容反转 |
public int length() | 返回对象内容长度 |
public String toString() | 通过toString就可以实现把StringBuilder转换为String |
public class Test {
public static void main(String[] args) {
StringBuilder sb1 = new StringBuilder();
// append方法:添加数据并返回StringBuilder对象本身
sb1.append(3);
sb1.append('月');
sb1.append(18);
sb1.append('日');
sb1.append(22.42);
sb1.append("我在想什么");
System.out.println(sb1);
// StringBuilder支持链式编程
StringBuilder sb2 = new StringBuilder();
sb2.append("nam的").append("正真").append("个一");
// reverse方法:将对象的内容反转
System.out.println(sb2.reverse());
// 注意:StringBuilder只是拼接字符串的手段:效率好;
// 最终的目的还是要恢复String类型
StringBuilder sb3 = new StringBuilder();
sb3.append("唱跳").append("rap");
// toString方法:恢复成string类型
/*
为什么要恢复成string类型:
大多数人的习惯,都习惯接收一个string类型的密码
*/
String result = sb3.toString();
checkPassWord(result);
}
// 检查密码
public static void checkPassWord(String passWord){
System.out.println(passWord);
}
}
String类拼接字符串,由于String类是不可变字符串,所以一个“+”符号,就要在堆内存中产生一个新对象,并且拼接完后,又会将原对象当做垃圾扔掉,非常浪费内存,性能也不好。
StringBuilder类拼接字符串,只需要创建一个新对象,而且每拼接完一次,就会返回原对象,效率高,性能好。
为什么拼接、反转字符串的时候要用StringBuilder?
String:内容不可变、拼接字符串性能差‘
StringBuilder:内容是可变的、拼接字符串性能好、书写优雅
定义字符串使用String;
拼接、修改等操作字符串使用StringBuilder。
设计一个方法用于输出任意整型数组的内容,要求输出成如下格式
"该数组的内容为:[11,22,33,44,55,66]"
1、定义一个方法,用于接收一个数组,将数组内容输出
2、当传入的数组不为null时,才开始拼接,否则返回null
3、定义循环,遍历数组内容
4、在循环外,定义一个空的StringBuilder对象,用于拼接遍历出的数组内容,先拼个左中括号,利用有参构造器,省一行代码
5、在循环内,判断每次遍历到的这个数据 是否为 最后一个,是则不用", “隔开,否则用”, "隔开
6、拼一个右中括号
7、将拼接结果恢复成字符串类型并返回
8、模拟一组数据,传入方法
/*
需求:
设计一个方法用于输出任意整型数组的内容,要求输出成如下格式:
"该数组的内容为:[11,22,33,44,55]"
*/
public class Test02 {
public static void main(String[] args) {
int[] a = {11, 22, 33, 44, 55};
String rs = printArr(a);
System.out.println("该数组内容为:"+rs);
System.out.println("---------------");
int[]b = null;
System.out.println("该数组内容为:"+printArr(b));
System.out.println("---------------");
int[]c = {};
System.out.println("该数组内容为"+printArr(c));
}
// 定义一个方法,用于接收一个数据,将数组内容输出
public static String printArr(int[]arr) {
// 当传入的数组不为null时,才开始拼接。
if (arr != null) {
// 在循环外,定义一个空的StringBuilder对象,用于拼接遍历出的数组内容
// 利用有参构造器,先拼一个左中括号
StringBuilder sb = new StringBuilder("[");
// 定义循环,遍历数组内容
for (int i = 0; i < arr.length; i++) {
// 在循环内,判断每次遍历到的数字是否为最后一个,不是加上","隔开,是则不用
sb.append(arr[i]).append(i == arr.length - 1 ? "" : ",");
}
// 拼一个右中括号
sb.append("]");
// 将拼接结果恢复成字符串类型并返回
return sb.toString();
} else {
// 是null则返回null
return null;
}
}
}
控制台输出结果:
System的功能是通用的,都是直接用类名调用即可,所以System不能被实例化。
方法名 | 说明 |
public static void exit | 终止当前运行的Java虚拟机,非零表示异常终止 |
public static long currentTimeMillis() | 返回当前系统的时间毫秒值形式 |
public static void arraycopy(数据源数组,起始索引,目的地数组,起始索引,拷贝个数) | 数组拷贝 |
计算机来历:
时间毫秒值:
public class SystemExitTest {
public static void main(String[] args) {
System.out.println("程序开始.......");
System.exit(0);
// System的exit方法:JVM终止(程序终止)
}
}
public class currentTimeMillisTest {
public static void main(String[] args) {
// 计算机认为起源时间:返回1970-1-1 00:00:00 走到刺客的总的毫秒值:时间毫秒值
long time = System.currentTimeMillis();
System.out.println(time);
// 分析开始之前,先记录一个起始时间
long startTime = System.currentTimeMillis();
// 进行时间的计算:性能分析
for (int i = 0; i < 10000; i++) {
System.out.println("输出:"+i);
}
// 分析结束,记录一个结束时间
long endTime = System.currentTimeMillis();
// 将毫秒值转换成秒值:(结束时间 - 开始时间) /1000.0秒
System.out.println((endTime - startTime)/1000.0+"s");
}
}
public class ArraycopyTest {
public static void main(String[] args) {
// 原数组
int[] arr1 = {11,22,33,44,55};
// 新数组
int[] arr2 = new int[6];
// 拷贝数组内的位置:1和2
System.arraycopy(arr1,1,arr2,1,2);
// 输出arr2
System.out.println(Arrays.toString(arr2));
}
}
用于解决浮点型运算精度失真的问题。
创建BigDecimal对象来封装浮点型数据(最后的方式是调用方法)
public static BigDecimal valueOf(double val): 封装浮点数成为BigDecimal对象。
方法名 | 说明 |
public BigDecimal add(BigDecimal b) | 加法 |
public BigDecimal subtract(BigDecimal b) | 减法 |
public BigDecimal multiply(BigDecimal b) | 乘法 |
public BigDecimal divide(BigDecimal b) | 除法 |
public BigDecimal divide(另一个BigDecimal对象,精确几位,舍入模式) | 除法 |
注意事项
【强制】 禁止使用构造方法BigDecimal(double) 的方式把 double 值转化为 BigDecimal 对象。
说明:BigDecimal(double) 存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
如:BigDecimal g = new BigDecimal(0.1F); 实际的存储值为:0.10000000149。
正例: 优先推荐入参为 String 的构造方法,或使用 BigDecimal 的 valueOf
方法,此方法内部其实执行了 Double 的 toString,而 Double 的 toString 按 double 的实际能表达的精度对尾数进行了截断
BigDecimal recommend1 = new BigDecimal("0.1");
BigDecimal recommend2 = BigDecimal.valueOf(0.1); // 推荐
public class BigDecimalTest {
public static void main(String[] args) {
// 浮点型运算的时候直接+-*/可能会出现数据失真(精度问题)
System.out.println(0.09+0.01);
System.out.println(1.0-0.32);
System.out.println(1.005*50);
System.out.println(1.005/50);
System.out.println("---------------");
double a =0.1;
double b =0.2;
double c = a+b;
System.out.println("a+b="+c);
System.out.println("---------------");
// 包装浮点型数据成为大数据对象BigDecimal
BigDecimal a1 = BigDecimal.valueOf(a);
BigDecimal b2 = BigDecimal.valueOf(b);
// 加减乘除
BigDecimal c1 = a1.add(b2);
BigDecimal c2 = a1.subtract(b2);
BigDecimal c3 = a1.multiply(b2);
BigDecimal c4 = a1.divide(b2);
// 输出加减乘除
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
System.out.println("-------------");
/* BigDecimal只是用来计算的手段,最终目的还是要恢复成double类型
BigDecimal的doubleValue方法可以直接转成double
*/
double rs1 = c1.doubleValue();
double rs2 = c2.doubleValue();
double rs3 = c3.doubleValue();
double rs4 = c4.doubleValue();
checkValue(rs1);
checkValue(rs2);
checkValue(rs3);
checkValue(rs4);
System.out.println("-------------");
BigDecimal g1 = BigDecimal.valueOf(10.0);
BigDecimal g2 = BigDecimal.valueOf(3.0);
// RoundingMode.HALF_UP舍入模式
BigDecimal e1 = g1.divide(g2,2, RoundingMode.HALF_UP);
System.out.println(e1);
}
public static void checkValue(double i){
System.out.println(i);
}
}
控制台输出结果: