public static String toString(Object o) // 获取对象的字符串表现形式
public static boolean equals(Object a, Object b) // 比较两个对象是否相等
public static boolean isNull(Object obj) // 判断对象是否为null
public static boolean nonNull(Object obj) // 判断对象是否不为null
1.toString(获取对象的字符串表现形式)
默认情况下,因为object类中的toString方法返回的是地址值,所以默认打印地址值 如果我们要打印属性值,就必须重写toString方法 toString方法的结论 如果我们打印一个对象,想要看到属性值,那就必须重写toString方法 在重写的方法中,把对象的属性值进行拼接
cpp
public class objectdemo1 {
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1);//Object.Student@b4c966a
String s2 = s1.toString();
System.out.println(s2);//Object.Student@b4c966a
//默认情况下,因为object类中的toString方法返回的是地址值,所以默认打印地址值
//如果我们要打印属性值,就必须重写toString方法
//toString方法的结论
//如果我们打印一个对象,想要看到属性值,那就必须重写toString方法
//在重写的方法中,把对象的属性值进行拼接
}
}
重写之后
cpp
@Override
public String toString() {
return name+","+age;
}
public class objectdemo1 {
public static void main(String[] args) {
Student s1 = new Student("zhangsan",18);
System.out.println(s1);//zhangsan,18
String s2 = s1.toString();
System.out.println(s2);//zhangsan,18
//默认情况下,因为object类中的toString方法返回的是地址值,所以默认打印地址值
//如果我们要打印属性值,就必须重写toString方法
//toString方法的结论
//如果我们打印一个对象,想要看到属性值,那就必须重写toString方法
//在重写的方法中,把对象的属性值进行拼接
}
}
2.equals(比较两个对象是否相等)
默认比的是地址值,由于我们创建对象肯定创建出不同的对象**,在堆区会开辟不同的内存空间,所以地址值肯定不一样,所以我们就要重写父类object里的equals方法**
cpp//public static boolean equals(Object a, Object b) 比较两个对象是否相等 public class objectdemo2 { public static void main(String[] args) { Student s1 = new Student(); Student s2 = new Student(); System.out.println(s1.equals(s2));//比的是地址值 } }
结果
重新父类的equals方法
cpp
@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);
}
如果我们比较属性值:
cpp
//public static boolean equals(Object a, Object b) 比较两个对象是否相等
public class objectdemo2 {
public static void main(String[] args) {
Student s1 = new Student("张三",18);
Student s2 = new Student("张三",18);
System.out.println(s1.equals(s2));//比的是属性值
}
}
结果
cpp
//public static boolean equals(Object a, Object b) 比较两个对象是否相等
public class objectdemo3 {
public static void main(String[] args) {
String s1 = "abc";
StringBuffer sb = new StringBuffer("abc");
System.out.println(s1.equals(sb));//false
//因为equals方法是被s1调用的,而s1是字符串
//所以equals要看String类中的
//如果是字符串,则比较内部属性值
//如果参数不是字符串,直接返回false
System.out.println(sb.equals(s1));//false
//因为equals方法是被sb调用的,而sb是不是字符串是StringBuffer
//所以equals要看StringBuffer类中的
//因为StringBuffer没有重写equals方法,所以默认使用的是父类object类的equals方法
//所以比较的是地址值
//而这里s1和sb的地址值不一样,所以返回false
}
}
结论:
3.浅克隆和深克隆
在Java中,实现浅克隆通常意味着你需要重写对象的clone()方法。Java中的Object类提供了一个默认的clone()方法,但这个默认实现是受保护的,因此你需要让你的类实现Cloneable接口(尽管这个接口是一个标记接口,没有任何方法),并且重写clone()方法以使其为public。
浅克隆
细节:
cpp
public class objectdemo5 {
public static void main(String[] args) throws CloneNotSupportedException {
Day day = new Day(2024, 6, 6);
// 创建一个Animal对象
Animal a = new Animal("小黑", 2, day);
// 浅克隆这个Animal对象
//先是object cloneA=a.clone();
//然后强转成Animal类型
// Animal cloneA=(Animal)a.clone();
Animal cloneA = (Animal) a.clone();
System.out.println(cloneA);
}
}
cpp
package Object;
import java.util.Objects;
// 假设我们有一个简单的类Animal,它包含基本数据类型和另一个对象的引用
public class Animal implements Cloneable{
private String name;
private int age;
private Day day; 假设Day是另一个类,并且我们想要浅克隆它
public Animal(String name, int age, Day day) {
this.name = name;
this.age = age;
this.day = day;
}
public Animal() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Day getDay() {
return day;
}
public void setDay(Day day) {
this.day = day;
}
// 重写clone方法以实现浅克隆
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
// toString方法(可选,但有助于调试)
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age=" + age +
", day=" + day +
'}';
}
}
cs
package Object;
public class Day {
private int year;
private int month;
private int day;
public Day(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public Day() {
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
public String toString() {
return "Day{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
}
结果:
clone 方法是浅拷贝,对象内属性引用的对象只会拷贝引用地址,而不会将引用的对象重新分配内存,相对应的深拷贝则会连引用的对象也重新创建。
说白了 浅克隆 是克隆的对象和被克隆的对象共享一块内存,其实一方改变,则另一方也跟着改变
深克隆
深克隆我们可以导入第三方工具类
cpp
//用第三方工具
//编写代码
Gson gson = new Gson();
//把对象变成字符串
String s = gson.toJson(a);//克隆Animal a类
//再把字符串变成对象即可
Animal animal = gson.fromJson(s, Animal.class);
//试一下是不是深克隆 animal没有变即深克隆
day.setYear(2023);
//打印对象
System.out.println(animal);//拷贝之后的结果
结果
说白了 深克隆 是克隆的对象和被克隆的对象不是一块内存,其实一方改变,则另一方也不会跟着改变,克隆出来的本质是拷贝了一个副本,操作的是自己属于的那块内存
Objects
cpp
public static void main(String[] args) {
Student s1 = null;
Student s2 = new Student("zhangsan", 18);
//判断对象是否为null
boolean result = Objects.equals(s1, s2);
System.out.println(result);//false
//细节:
//1.方法的底层会判断s1是否为null,如果为null,直接返回false
//2.如果s1不为null,那就利用s1再次调用equals方法
//3.此时s1是Student类型,所以最终还是会调用Student类型中的equals方法
//如果没有重写,比较的是地址值,如果重写了,比较的就是属性值了
结果:
public static boolean isNull(Object obj) // 判断对象是否为null
public static boolean nonNull(Object obj) // 判断对象是否不为null
cpp
Student s3 = new Student("zhangsan", 18);
Student s4 = null;
System.out.println(Objects.isNull(s3)); 判断对象是否为null,为null返回true
System.out.println(Objects.isNull(s4));
结果:
cpp
// public static boolean nonNull(Object obj)// 判断对象是否不为null
Student s5 = new Student("zhangsan", 18);
Student s6 = null;
System.out.println(Objects.nonNull(s5));//判断对象是否为不null,如果不为null返回true
System.out.println(Objects.nonNull(s6));
结果