Object类

API

API(Application Programming Interface):应用程序编程接口
Java API:就是Java提供给我们使用的类,这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用。

Object类

Object类:类层次结构的根类,所有类都直接或者间接的继承该类。
构造方法:public Object()
Object类属于java.lang包下的类,该包下的类不需要导入就可以访问该包下的类的成员

hashCode()方法
//返回该对象的哈希码值。默认情况下,该方法会根据对象的地址来计算。
public int hashCode()

不同对象的hashCode()一般不会相同 ,但是同一个对象的hashCode()值肯定相同。
不是对象的实际地址值,可以理解为逻辑地址值。

public class Demo {
    public static void main(String[] args) {
        Object obj1=new Object();
        Object obj2=new Object();
        System.out.println(obj1.hashCode());
        System.out.println(obj2.hashCode());
    }
}
/*
输出结果:
460141958
1163157884
*/
getClass()方法
//返回此 Object 运行时的类以及所在的包。
public final Class getClass()
public class Demo2 {
    public static void main(String[] args) {
        //getClass()
        Object obj1=new Object();
        Object obj2=new Object();
        System.out.println(obj1.getClass());
        System.out.println(obj2.getClass());
        Student s1=new Student();
        System.out.println(s1.getClass());
        System.out.println(obj1.getClass().getName());
        System.out.println(obj1.getClass()==obj2.getClass());
        System.out.println(obj1.getClass()==s1.getClass());
    }
}
class Student{}
/*
运行结果:
class java.lang.Object
class java.lang.Object
class com.xupt.Demo2.Student
java.lang.Object
true
false
*/
//可通过getName()方法获取对象的真实类的全名称
//public String getName()
toString()方法
//返回该对象的字符串表示。
public String toString() {
	return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public class Test2 {
    public static void main(String[] args) {
        Object obj=new Object();
        System.out.println(obj);
        System.out.println(obj.toString());
    }
}
//输出obj默认会调用toString()方法
/*
运行结果:
java.lang.Object@1b6d3586
java.lang.Object@1b6d3586
*/

对于我们来说,获取类名和地址值没有什么意义,所以我们可以重写toString()方法

public class Student {
    String name;
    int age;
    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString()
    {
        return "姓名:"+this.name+"\n年龄:"+this.age;
    }
}
public class Demo {
    public static void main(String[] args) {
        Student s1=new Student("张三",20);
        //我们想让toString返回的是姓名和年龄,需要重写toString方法
        System.out.println(s1.toString());
    }
}
/*
输出结果:
姓名:张三
年龄:20
*/
equals()方法
//指示一些其他对象是否等于此。
 public boolean equals(Object obj) {
	return (this == obj);
}

对于字符串即String类来说,两个字符串字面值相等,就代表两个对象相同
String类中将equals()方法重写了,用于比较两个字符串字面值是否相等

public class Demo {
    public static void main(String[] args) {
        String s1="abc";
        String s2="abc";
        boolean b=s1.equals(s2);
        System.out.println(b);
    }
}
/*
输出结果:
true
*/

我们同样可以重写一个类中的equals方法

//我们将equals方法重写为如果Student类对象的name和age相同,就表示这两个对象相同
public class Student {
    String name;
    int age;
    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public boolean equals(Object obj)
    {
    	return this.name.equals(s.name)&&this.age==s.age;
    }
}
public class Demo4 {
    public static void main(String[] args) {
        Student s1=new Student("张三",20);
        Student s2 = new Student("张三",20);
        //在学生类中,如果姓名和年龄相等,我们就认为这两个对象相等,则需要重写equals方法
        System.out.println(s1.equals(s2));
    }
}
/*
输出结果:
true
*/

在编程中,我们要提高程序的健壮性,即让其更加周全,还要提高程序的效率
如果我们传入一个非Student类的对象,程序就会报错
如果传入这个对象自身,那么我们可以直接返回true来提高效率

//改进如下
@Override
public boolean equals(Object obj)
{
    if(this==obj)
        return true;
    //判断传入的对象是否为该类对象
    if(!(obj instanceof Student))
        return false;
    Student s=(Student)obj;
    return this.name.equals(s.name)&&this.age==s.age;
}
clone()方法

克隆分为浅克隆和深克隆,在此我们只讲浅克隆
对象的深克隆后面讲:采用IO流来实现 使用 ObjectOutputStream 将对象写入文件中,然后再用ObjectInputStream读取回来

//创建并返回此对象的副本
protected Object clone()
                throws CloneNotSupportedException

clone()的权限修饰符是受保护的,在使用的时候,让该类重写该方法,并把该方法的权限修饰符改为public
如果一个对象需要调用clone方法,那么该对象所属的类必须要实现Cloneable接口。

//Cloneable接口中没有任何抽象方法
//接口中如果没有定义任何抽象方法,这种接口叫做标记接口
class Student implements Cloneable{
    String name;
    int age;
    public Student() {}
    //重写clone方法,将权限修饰符改为public
    //要抛出CloneNotSupportedException异常
    @Override
    public Object clone() throws CloneNotSupportedException {
    	//我们不需要重写父类的clone方法,直接调用父类的clone方法
        return super.clone();
    }
}
public class Demo {
	//此处也要抛出CloneNotSupportedException异常
    public static void main(String[] args) throws CloneNotSupportedException {
	    Student s1=new Student();
	   	s1.age=15;
	   	//因为返回的是一个Object的对象,所以要向下转型
	    Student s2=(Student)s1.clone();
	    s2.age=18;
	    System.out.println(s1.age);
	    System.out.println(s2.age);
	    //s1和s2的地址值是不同的
	    System.out.println(s1);
        System.out.println(s2);
    }
}
/*
运行结果:
15
18
com.xupt.Demo.Student@1b6d3586
com.xupt.Demo.Student@4554617c
*/

如果被克隆的对象中维护了另外一个类的对象,这时候只是克隆被维护的对象的地址,而没有把该对象也克隆一份。

class Student implements Cloneable{
    String name;
    int age;
    Book book;
    public Student() {}
    public Student(String name, int age,Book book)
    {
        this.name = name;
        this.age = age;
        this.book=book;
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
//学生在阅读的书籍
class Book{
    String name;
    public Book(){}
    public Book(String name)
    {
        this.name=name;
    }
}
public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
       Book b=new Book("Math");
       Student s1=new Student("张三",15,b);
       Student s2=(Student) s1.clone();
       s2.book.name ="Chinese";
       System.out.println(s1.book.name);
       System.out.println(s2.book.name);
    }
}
/*
运行结果:
Chinese
Chinese
*/

过程(过程中就暂且不涉及创建对象的内存操作):

  1. 定义一个Book类型的引用b指向一个Book类型的对象,定义一个Student类型的引用s1指向一个Student类型的对象,在该对象中存在一个Book类型的引用b指向Book类型的对象,如图所示
  2. 通过clone()方法将s1引用指向的对象克隆一份,在堆内存中新开辟一个空间存储这个对象,并把地址值赋值给引用s2
  3. 此时通过s2引用改变堆内存中Book对象name的值(堆内存中只有一个Book类型的对象),Math被Chinese覆盖
  4. 此时该Book类型的对象共有三个引用指向它,如图所示
  5. 当我们再次通过s1的引用访问该Book对象的name值时,打印出来的自然是Chinese
    需要注意的是:Book对象自始至终只有一个,s2中b克隆的只是s1中b的地址值,Book对象不会再被克隆一份

在这里插入图片描述

### Object 的作用 在 Java 中,`Object` 是所有的根。每个无论是否显式声明继承,都会直接或间接继承自 `Object` 。这使得 `Object` 的方法能够被所有对象使用,提供了基础功能支持。`Object` 的定义确保了所有对象都具备一些通用的行为,例如对象的比较、克隆、字符串表示等。 ### 常见方法及使用 #### 1. `toString()` 此方法返回对象的字符串表示形式。默认情况下,返回的字符串格式为 `名@哈希码`,例如 `java.lang.Object@1b6d3586`。在实际开发中,通常会重写此方法以提供更有意义的对象描述。 示例: ```java Object obj = new Object(); System.out.println(obj.toString()); // 输出:java.lang.Object@哈希码 ``` 重写示例: ```java @Override public String toString() { return "Custom String Representation"; } ``` #### 2. `equals(Object obj)` 默认情况下,`equals()` 方法用于比较两个对象的引用是否指向同一个对象实例。然而,在实际开发中,通常需要根据对象的实际属性来判断相等性,因此需要重写此方法。例如,当对象被存储在 `Map` 或 `Set` 中时,如果两个对象的 `hashCode()` 相同,则会调用 `equals()` 方法进行进一步比较。 #### 3. `hashCode()` 此方法返回对象的哈希码值。通常与 `equals()` 方法一起重写,以确保两个相等的对象具有相同的哈希码。这对于基于哈希的集合(如 `HashMap` 和 `HashSet`)的正确行为至关重要。 #### 4. `clone()` 此方法用于创建并返回对象的一个副本。要使用此功能,需要实现 `Cloneable` 接口并重写 `clone()` 方法,否则会抛出 `CloneNotSupportedException` 异常。 #### 5. `getClass()` 此方法返回运行时的 `Class` 对象,可以用于反射操作。 #### 6. `notify()` 和 `wait()` 这些方法用于线程间的协作。`wait()` 方法使当前线程等待,直到另一个线程调用 `notify()` 或 `notifyAll()` 方法。 ### Object 的重要性 由于 `Object` 是所有的超,因此它提供了一种统一的方式来处理所有对象。例如,可以通过 `Object` 类型的引用变量来引用任何类型的对象,从而实现多态性。 此外,`Object` 提供的方法为对象的基本操作奠定了基础。例如,`toString()` 方法使得对象可以以字符串形式输出,便于调试;`equals()` 和 `hashCode()` 方法确保了对象在集合中的正确行为;`clone()` 方法提供了对象复制的机制。 ### 示例代码 以下是一个重写 `toString()` 和 `equals()` 方法的示例: ```java public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Person{name='" + name + "', age=" + age + "}"; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; Person person = (Person) obj; if (age != person.age) return false; return name != null ? name.equals(person.name) : person.name == null; } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值