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}