作为一名对技术充满热情的学习者,我一直以来都深刻地体会到知识的广度和深度。在这个不断演变的数字时代,我远非专家,而是一位不断追求进步的旅行者。通过这篇博客,我想分享我在某个领域的学习经验,与大家共同探讨、共同成长。请大家以开放的心态阅读,相信你们也会在这段知识之旅中找到启示。
文章目录
- 前言
- 一、Object类的基本概念
- 二、常用的方法
- 三、练习如何使用Object类的常用方法
- 案例题目:
- 题目扩展:
- 四、常见面试题
- 总结
前言
我们开始新的模块学习java常用类的概述和使用,今天我们就来聊聊Object类
一、Object类的基本概念
- java.lang.Object类是Java语言中类层次结构的根类,也就是说任何一个类都是该类的直接或者间
接子类。 - 如果定义一个Java类时没有使用extends关键字声明其父类,则其父类为 java.lang.Object 类。
- Object类定义了“对象”的基本行为, 被子类默认继承。
二、常用的方法
在Java中,Object类是所有类的根类。换句话说,每个类都直接或间接地继承自Object类。Object类定义了一些基本的方法,这些方法可以在所有Java对象中使用,包括:
-
equals(Object obj):用于比较两个对象是否相等。默认情况下,equals方法比较的是对象的引用,即判断两个对象是否指向内存中的同一位置。但是,可以在子类中重写equals方法以实现自定义的相等性比较。
-
hashCode():返回对象的哈希码值。哈希码值是根据对象的内存地址计算得出的,它通常用于在哈希表等数据结构中确定对象的存储位置。
-
toString():返回对象的字符串表示形式。默认情况下,toString方法返回的是类名后跟该对象的哈希码值的十六进制表示。通常,我们会在子类中重写toString方法,以返回对象更有意义的字符串表示形式。
-
getClass():返回对象的运行时类(Runtime Class)。可以使用getClass方法获取对象所属的类的信息,包括类的名称、包名等。
-
clone():用于创建并返回当前对象的一个拷贝。需要注意的是,clone方法是浅拷贝,即它只会复制对象的字段值,而不会复制对象引用的其他对象。如果需要实现深拷贝,则需要在子类中重写clone方法并对引用类型的字段进行单独处理。
-
finalize():用于在对象被垃圾回收之前执行清理操作。然而,由于finalize方法的执行时机不确定,而且在现代Java中已经不推荐使用显式的垃圾回收技术,因此finalize方法已经不推荐使用。
Object类的存在使得Java的类体系具有统一的根基础,提供了一组通用的方法,这些方法可以被所有类所使用,同时也为开发者提供了便利。
- 我们将详细讲解一下下面常用的方法:
三、练习如何使用Object类的常用方法
-
案例题目:
- 编程实现Student类的封装,特征:学号(id)和姓名,要求提供打印所有特征的方法。
- 编程实现StudentTest类,在main方法中使用有参方式构造两个Student类型的对象并打印特征。
-
题目扩展:
- 如何实现以姓名作为基准判断两个对象是否相等?以及以学号和姓名同时作为基准判断两个对象是否相等?
import java.util.Objects;
public class Student extends Object {
private int id; // 用于描述学号的成员变量
private String name; // 用于描述姓名的成员变量
public Student() {
}
public Student(int id, String name) {
setId(id);
setName(name);
}
public int getId() {
return id;
}
public void setId(int id) {
if (id > 0) {
this.id = id;
} else {
System.out.println("学号不合理哦!!!");
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return id == student.id &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
/*
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (id != student.id) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
return result;
}
*/
/**
* 为了比较两个对象的内容,也就是学号信息需要重写该方法
*/
// Student this = s1;
// Object obj = s2;
/*
@Override
public boolean equals(Object obj) {
// 当调用对象和参数对象指向同一个对象时,则内容一定相同
if (this == obj) return true;
// 当调用对象为不为空而参数对象为空时,则内容一定不相同
if (null == obj) return false;
// 判断obj指向的对象是否为Student类型的对象,若是则条件成立,否则条件不成立
if (obj instanceof Student) {
Student ts = (Student) obj;
// 以学号作为基准判断两个对象是否相等 int是基本数据类型,内存空间中放的就是数据本身,使用 == 可以判断数据是否相同
//return this.getId() == ts.getId();
// 以姓名作为基准判断两个对象是否相等 String是引用数据类型,内存空间中放的是地址,使用 == 判断地址是否相同
// 也就是判断两个对象中姓名字符串的地址是否相同,不够完美
//return this.getName() == ts.getName();
return this.getName().equals(ts.getName()); // 比较姓名字符串的内容是否相同
}
// 否则类型不一致没有可比性,则内容一定不相同
return false;
}
*/
/**
* 为了使得该方法的结果与equals方法的结果保持一致,从而满足Java官方的常规协定,需要重写该方法
*/
/*
@Override
public int hashCode() {
//return getId(); // 不再代表内存地址的编号了
final int type = 12;
//return type*31 + getId();
return type*31 + getName().hashCode();
}
*/
/**
* 为了返回更有意义的字符串数据,则需要重写该方法
*/
/*
@Override
public String toString() {
return "Student[id = " + getId() + ", name = " + getName() + "]";
}
*/
}
public class StudentTest {
public static void main(String[] args) {
// 1.使用有参方式构造Student类型的两个对象并判断是否相等
Student s1 = new Student(1001, "zhangfei");
//Student s2 = new Student(1002, "guanyu");
Student s2 = new Student(1001, "zhangfei");
//Student s2 = s1; // 表示s2和s1都指向了同一个对象,地址相同了
// 下面调用从Object类中继承下来的equals方法,该方法默认比较两个对象的地址,可以查看源码验证
// 当Student类中重写equals方法后,则调用重写以后的版本,比较内容
//boolean b1 = s1.equals(s2);
//Student s3 = null;
//boolean b1 = s1.equals(s3);
//Student s3 = s1;
boolean b1 = s1.equals(s2);
System.out.println("b1 = " + b1); // false true
System.out.println(s1 == s2); // 比较地址 false
System.out.println("----------------------------------------------------------");
// 下面调用从Object类中继承下来的hashCode方法,获取调用对象的哈希码值(内存地址的编号)
// 当Student类中重写hashCode方法后,则调用重写以后的版本
int ia = s1.hashCode();
int ib = s2.hashCode();
System.out.println("ia = " + ia);
System.out.println("ib = " + ib);
System.out.println("----------------------------------------------------------");
// 下面调用从Object类中继承下来的toString方法,获取调用对象的字符串形式:包名.类名@哈希码值的十六进制
// 当Student类中重写toString方法后,则调用重写以后的版本:Student[id = 1001, name = zhangfei]
String str1 = s1.toString();
System.out.println("str1 = " + str1); // com.lagou.task11.Student@55d
System.out.println(s1); // 当打印一个引用变量时会自动调用toString方法
String str2 = "hello" + s1;
System.out.println("str2 = " + str2);
}
}
以上代码对常用方法进行了使用,注释需自己看
四、常见面试题
-
equals() 方法和 == 运算符有什么区别?
-
equals() 方法: 用于比较两个对象的内容是否相等。默认情况下,equals() 方法比较的是对象的引用地址,即两个对象是否指向内存中的同一块区域。但是,可以通过在类中重写 equals() 方法来改变其默认行为,实现自定义的对象相等性比较。
-
== 运算符: 用于比较两个对象的引用是否相等,即它们是否指向内存中的同一块区域。即使是同一个对象的拷贝(即两个对象的内容相同但是引用不同),使用 == 运算符也会返回 false。
-
区别: equals() 方法比较的是对象的内容,而 == 运算符比较的是对象的引用。在实际应用中,应根据具体的需求来选择使用 equals() 方法还是 == 运算符。
-
-
hashCode() 方法的作用是什么?
- hashCode() 方法: 返回对象的哈希码值。哈希码值是根据对象的内存地址计算得出的一个整数,它通常用于在哈希表等数据结构中确定对象的存储位置。在 Java 中,hashCode() 方法被广泛用于集合类(如HashMap、HashSet等)的实现中,以提高元素的查找效率。
-
为什么重写 equals() 方法时通常也要重写 hashCode() 方法?
- 在 Java 中,如果两个对象在 equals() 方法中被判定为相等,那么它们的 hashCode() 方法应该返回相同的值。
- 这是因为在使用哈希表等数据结构时,对象的 hashCode() 值用于确定对象在表中的存储位置。如果两个对象在 equals() 方法中被判定为相等,但是它们的 hashCode() 方法返回的值不同,这将导致在哈希表中存储的位置不一致,进而可能导致在查找、插入等操作时出现问题。
- 因此,为了保持一致性,在重写 equals() 方法时通常也需要重写 hashCode() 方法,以确保对象相等时它们的哈希码值相同。
-
toString() 方法的作用是什么?
- toString() 方法: 返回对象的字符串表示形式。默认情况下,toString() 方法返回的是对象的类名后跟该对象的哈希码值的十六进制表示。但是,可以通过在类中重写 toString() 方法来返回对象更有意义的字符串表示形式,以便于调试、日志输出等场景的使用。
-
finalize() 方法的作用是什么?
- finalize() 方法: 用于在对象被垃圾回收之前执行清理操作。然而,由于 finalize() 方法的执行时机不确定(甚至有可能不会被执行),而且在现代 Java 中已经不推荐使用显式的垃圾回收技术,因此 finalize() 方法已经不推荐使用,更好的方式是使用 try-with-resources 或者 try-finally 结构来进行资源的释放和清理。
总结
感谢大家抽出宝贵的时间来阅读博主的博客,新人博主,感谢大家关注点赞,祝大家未来的学习工作生活一帆风顺,加油!!!