JavaAPI(2)
JavaAPI(2)
一、Object类
Object是Java中的顶级父类。所有的类都直接或者间接的继承与Object类
1、Object的构造方法
- 只有空参构造——
public Object()
class Person {private String name;private int age;public Person() {super(); // 不写,系统会默认加上}public Person(String name, int age) {super(); // 不写,系统会默认加上this.name = name;this.age = age;}
}
当你创建一个子类对象时,子类的构造函数会自动调用父类的构造函数。这是因为子类需要确保父类部分的初始化完成,以便能够正确使用从父类继承的属性和方法。
2、Object常用的成员方法
2.1toString()方法
public String toString()——返回对象的字符串表示形式
- 当没有在方法中重写
toString()方法时,默认打印一个对象时,底层会调用父类Object中的toString方法,打印出对象的地址值 - 如果想要打印出内容的属性值,则需要在子类中重写
toString方法
示例:
// 1.toString 返回对象的字符串表示形式Object object = new Object();String s = object.toString();System.out.println(s); // 输出: java.lang.Object@4eec7777// 没有重写toString方法时// 细节:// System:类名// out:静态变量// System.out:获取打印的对象// println():方法// 核心逻辑:打印一个对象时,底层会调用对象的toString方法,把对象变成字符串Student st = new Student();String s1 = st.toString();System.out.println(s1); // 输出: com.api.a04objectdemo04.Student@41629346// 若要打印出的内容是属性值,则需要造子类中重写toString方法System.out.println(s1); // 输出: Student{name = null, age = 0}// 所以要实现本方法时,且要打印出它的属性值时,需要重写
2.2equal()方法
public boolean equals(object obj)——比较两个对象是否相等
- 如果没有调用重写的
equals方法,那么就默认使用Object中的方法进行比较,比较的是地址值是否相等 - 一般地址值对于我们来讲意义不大,所以我们会进行重写,比较内部的属性值
重写的代码:
@Overridepublic 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);}
示例:
// 2.equal 比较两个对象是否相等Student s2 = new Student();Student s3 = new Student();// 如果没有调用重写equals方法,那么就默认使用Object中的方法进行比较,比较的是地址值是否相等boolean result = s2.equals(s3);System.out.println(result); // 输出: false// 一般来讲地址值对于我们的意义不大,所以我们会重写// 重写之后比较的就是对象内部的属性值了Student a1 = new Student("小明", 20);Student a2 = new Student("小明", 20);boolean result01 = a1.equals(a2);System.out.println(result01); // 输出: true
拓展内容:
String和StringBuilder类的比较
public static void main(String[] args) {// 拓展String s = "abc";StringBuilder sb = new StringBuilder("abc");System.out.println(s.equals(sb)); // 输出: false// 因为equals方法是被s调用的,而s是字符串// 所以equals要看String类中的// 字符串中的equals方法,先判断地址值,再判断参数是否是字符串,再比较字符串是否相等// 如果是字符串,再比较内部的属性// 此处并不是字符串,所以输出为: falseSystem.out.println(sb.equals(s)); // 输出: false// 因为equals方法是被sb调用的,而sb是StringBuilder// 所以这里的equals方法要看StringBuilder中的equals方法// 那么在StringBuilder当中,没有重写equals方法// 使用的是Object中的// 在object当中默认是使用==号比较两个对象的地址值// 而这里的s和sb记录的地址值是不一样的,所以结果返回false}
2.3clone()方法
protected Object clone(int a)——对象克隆
使用场景:一般在游戏中会用于,玩家在不同服务区数据的克隆
- 该方法不能通过创建的对象直接调用,因为是在
Object中是protected修饰的(protected是不同包下的子类里面可以用,但子类创建的对象不能用) - 所以要想使用只能在子类中重写
clone()方法
在子类中的重写:
@Overrideprotected Object clone() throws CloneNotSupportedException {// 调用父类中的clone方法// 相当于让Java帮我们克隆一个对象,并把克隆之后的对象返回出去return super.clone();}
- 并且要将子类实现
Cloneable接口:
//Cloneable
// 如果一个接口里面没有抽象方法
// 表示当前的接口是一个标记性接口
// 现在cloneable表示一旦了实现,那么当前类的对象就可以被克隆
// 如果没有实现,当前类的对象就不能克隆
public class User implements Cloneable{……
}
在测试类中:
public static void main(String[] args) throws CloneNotSupportedException {// 对象克隆// 1.先创建一个对象int[] data = {1,2,3,4,5,6,7,8,9,10,11};User u1 = new User(1, "xiaoming", "123456", "sxacs", data);// 2.克隆对象// 不能直接创建对象调用,因为在Object中是protected修饰的// protected是不同包下的子类里面可以用,但是子类创建的对象不能用(只能在子类中重写clone()方法)// 细节:// 方法在底层会帮我们创建一个对象,并把原对象中的数据拷贝过去。// 书写细节://1.重写object中的clone方法//2.让javabean类实现cloneable接口//3.创建原对象并调用clone就可以了。User u2 = (User)u1.clone();// 验证Object中的克隆是深克隆还是浅克隆int[] arr = u1.getData();arr[2] = 10000;System.out.println(u1); // 输出: objectdemo03{id = 1, username = xiaoming, password = 123456, path = sxacs, data = [1, 2, 10000, 4, 5, 6, 7, 8, 9, 10, 11]}System.out.println(u2); // 输出: objectdemo03{id = 1, username = xiaoming, password = 123456, path = sxacs, data = [1, 2, 10000, 4, 5, 6, 7, 8, 9, 10, 11]}// 输出结果一下 Object中的克隆是浅克隆}
浅克隆和深克隆:
- 把A对象的属性值完全拷贝给B对象,也叫对象拷贝,对象复制
1、浅克隆
不管对象内部的属性是基本数据类型还是引用数据类型,都完全拷贝过来。
- 基本数据类型:直接拷贝值
- 引用数据类型:
- 字符串:存放在字符串常量池中,赋值也是将在常量池的地址赋值给克隆对象(复用)
- 引用数据类型数组:(
new出的),也是仍然会将之前new出的地址值赋给克隆对象
故:浅克隆的引用数据类型会与原对象共同操作使用一个地址的值(Object是浅克隆)
2、深克隆
- 基本数据类型:直接拷贝值
- 引用数据类型:
- 字符串:存放在字符串常量池中,赋值也是将在常量池的地址赋值给克隆对象(复用)
- 引用数据类型数组:再次
new一个内存,并将原来的值拷贝到新内存中,将新的地址值赋给克隆对象
故:深克隆的引用数据类型数组不会与原来的对象操作一个值(互不影响)
所以要想在上面的代码(父类Object)中实现深克隆则需要在子类重写的clone()方法中进行new操作:
@Override
protected object clone() throws CloneNotSupportedException{//调用父类中的clone方法//相当于让Java帮我们克隆一个对象,并把克隆之后的对象返回出去。//先把被克隆对象中的数组获取出来int[] data = this.data;//创建新的数组int[] newData =ew int[data.length];//拷贝数组中的数据for (int i = 0; i < data.length; i++) {newData[i]= data[i];}//调用父类中的方法克隆对象User u = (User) super.clone();//因为父类中的克隆方法是浅克隆,替换克隆出来对象中的数组地址值u.data = newData;return u;
}
二、Objects类
Objects是一个工具类,提供一些方法去完成一些功能
- 对于在创建对象时,可进行赋值为空的判断,避免空指针异常
1、equals()方法
public static boolean equals(object a, Object b)——先做非空判断,比较两个对象
2、isNull()方法
public static boolean isNull(object obj)——判断对象是否为null,为null返回true,反之
3、nonNull()方法
public static boolean nonNull(object obj)——判断对象是否为null,跟isNull的结果相反
示例:
public static void main(String[] args) {// Objects是一个工具类// 创建一个学生对象Student s1 = null;Student s2 = new Student("xiaoming", 20);// boolean result = s1.equals(s2);
// System.out.println(result); // 此时会报错 空指针异常// 比较两个对象的属性值是否相等if(s1 != null) {boolean result = s1.equals(s2);System.out.println(result);}else {System.out.println("调用者为空"); // 输出: 调用者为空}// 在这种情况下可以使用Objectsboolean result = Objects.equals(s1, s2);System.out.println(result); // false// 细节://1.方法的底层会判断s1是否为nul1,如果为nul1,直接返回false//2.如果s1不为null,那么就利用s1再次调用equals方法//3.此时s1是Student类型,所以最终还是会调用student中的equals方法。// 如果没有重写,比较地址值,如果重写了,就比较属性值。// 判断是否为空System.out.println(Objects.isNull(s1)); // trueSystem.out.println(Objects.isNull(s2)); // falseSystem.out.println(Objects.nonNull(s1)); // falseSystem.out.println(Objects.nonNull(s2)); // true}
