当前位置:网站首页>关于Object和Objects

关于Object和Objects

2022-01-15 02:32:05 朝上

关于Object和Objects

第1章 Object类

1.1概述

java.lang.Object类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。在对象实例化的时候,最终找的父类就是Object。

如果一个类没有特别指定父类, 那么默认则继承自Object类。例如:

public class MyClass /*extends Object*/ {
    
  	// ...
}

根据JDK源代码及Object类的API文档,Object类当中包含的方法有11个。今天我们主要学习其中的2个:

  • public String toString():返回该对象的字符串表示。
  • public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。

1.2 toString方法

方法摘要

  • public String toString():返回该对象的字符串表示。

toString方法返回该对象的字符串表示,其实该字符串内容就是对象的类型+@+内存地址值。

由于toString方法返回的结果是内存地址,而在开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它。

覆盖重写

如果不希望使用toString方法的默认行为,则可以对它进行覆盖重写。

例如自定义的Person类:

public class Person {
      
    private String name;
    private int age;

    @Override
    public String toString() {
    
        return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
    }

    // 省略构造器与Getter Setter
}

在IntelliJ IDEA中,可以点击Code菜单中的Generate...,也可以使用快捷键alt+insert,点击toString()选项。选择需要包含的成员变量并确定。如下图所示:

在这里插入图片描述

小贴士: 在我们直接使用输出语句输出对象名的时候,其实通过该对象调用了其toString()方法。

1.3 equals方法

方法摘要

  • public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。

调用成员方法equals并指定参数为另一个对象,则可以判断这两个对象是否是相同的。这里的“相同”有默认和自定义两种方式。

默认地址比较

如果没有覆盖重写equals方法,那么Object类中默认进行==运算符的对象地址比较,只要不是同一个对象,结果必然为false。

对象内容比较

如果希望进行对象的内容比较,即所有或指定的部分成员变量相同就判定两个对象相同,则可以覆盖重写equals方法。例如:

import java.util.Objects;

public class Person {
    	
	private String name;
	private int age;
	
    @Override
    public boolean equals(Object o) {
    
        // 如果对象地址一样,则认为相同
        if (this == o)
            return true;
        // 如果参数为空,或者类型信息不一样,则认为不同
        if (o == null || getClass() != o.getClass())
            return false;
        // 转换为当前类型
        Person person = (Person) o;
        // 要求基本类型相等,并且将引用类型交给java.util.Objects类的equals静态方法取用结果
        return age == person.age && Objects.equals(name, person.name);
    }
}

这段代码充分考虑了对象为空、类型一致等问题,但方法内容并不唯一。大多数IDE都可以自动生成equals方法的代码内容。在IntelliJ IDEA中,可以使用Code菜单中的Generate…选项,也可以使用快捷键alt+insert,并选择equals() and hashCode()进行自动代码生成。如下图所示:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

tips:Object类当中的其他方法,今后学习。

案例:

/** 
* 学生系统中,添加学生信息,并要求同名且同年龄的则为同一人,不允许添加至系统中。 
*  定义一个添加方法,可以将学生添加至容器中。
*/
package com.igeek.javase.code.ch06.object;

import java.util.Objects;

/** * @Version 1 * @Description TODO * @Athuor zhangquan * @Date 2021/9/8 9:45 */
public class Student extends Object {
    

    private String name;
    private int age;

    public Student(String name, int age) {
    
        this.name = name;
        this.age = age;
    }

    public Student() {
    
    }

    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;
    }


    //重写equals方法
    @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);
    }

    //重写hashCode方法
    @Override
    public int hashCode() {
    
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
    
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package com.igeek.javase.code.ch06.object;

import java.util.Arrays;
import java.util.Objects;

/** * @Version 1 * @Description TODO * @Athuor zhangquan * @Date 2021/9/8 13:32 */
public class StudentTest {
    

    private Student[] stus=new Student[3];
    private int index;

    public Student[] getStus() {
    
        return stus;
    }

    /** * 添加学生信息到该容器里面,当该容器里面有该学生的信息时(name,age都是一样)就添加失败 * @param stu 需要添加的学生对象 * @return 添加是否成功的结果 */
    public boolean add(Student stu){
    
        //判断是否需要数组扩容
        if(index >= stus.length){
    
            stus=Arrays.copyOf(stus,stus.length*3/2+1);
        }
        //只能存放不同的学生
        boolean flag=true;
        for (int i = 0; i < index; i++) {
    
            /*if(stus[i] != null){ if(stus[i].equals(stu)){ flag = false; } }*/
            //等于上面这种写法,Objects 类里面的方法对空指针安全(容忍空指针)
            if(Objects.equals(stus[i],stu)){
    
                flag = false;
            }
        }
        if(flag) {
    
            stus[index++]=stu;
            System.out.println("添加"+stu.getName()+"成功");
        }
        return flag;
    }

    @Override
    public String toString() {
    
        return "StudentTest{" +
                "stus=" + Arrays.toString(stus) +
                ", index=" + index +
                '}';
    }

    public static void main(String[] args) {
    
        StudentTest ST = new StudentTest();

        Student stu1 = new Student("张三",18);
        Student stu2 = new Student("张三",19);
        Student stu3 = new Student("张三",18);
        Student stu5 = new Student("李四",18);
        Student stu6 = new Student("王五",18);
        Student stu4 = stu1;

        //添加学生
        ST.add(stu1);
        ST.add(stu2);
        ST.add(stu3);
        ST.add(stu4);
        ST.add(stu5);
        ST.add(stu6);

        System.out.println(ST.toString());
    }
}

1.4 clone方法

源码:

@HotSpotIntrinsicCandidateprotected 
native Object clone() throws CloneNotSupportedException;

克隆一个具有该类同样信息的对象,地址不同,属性值相同!

克隆 "拷贝"

  • 若一个类的对象要使用clone(),则当前类必须实现Cloneable接口否则抛出异CloneNotSupportedException

  • Object中clone()是protected权限,只支持本类中调用自身的clone()

  • 若想调用其他类中的clone(),则必须要重写clone(),必须实现Cloneable接口

  • 浅克隆 和 深克隆

案例

public class CloneDemo1 implements Cloneable{
    

    //重写方法时,允许将protected权限 --> public权限
    //可以将返回值由 Object --> CloneDemo1 避免之后使用每次都要强转
    @Override
    protected CloneDemo1 clone() throws CloneNotSupportedException {
    
        return (CloneDemo1)(super.clone());
    }
}
public class CloneDemo2 /*extends Object*/ implements Cloneable{
    
    public static void main(String[] args) throws CloneNotSupportedException {
     
        CloneDemo2 demo1 = new CloneDemo2();
        //Object.clone()返回的是一个Object类的对象
        CloneDemo2 demo2 = (CloneDemo2)demo1.clone();
        System.out.println("demo1 = "+demo1);
        System.out.println("demo2 = "+demo2);
        System.out.println("---------------------------");
        CloneDemo1 demo3 = new CloneDemo1();
        CloneDemo1 demo4 = demo3.clone();
        System.out.println("demo3 = "+demo3);
        System.out.println("demo4 = "+demo4);
        System.out.println("---------------------------");
        //Object obj1 = new Object();
        //Object obj2 = obj1.clone();
    }
}

浅克隆 和 深克隆

发生在类和类之间有关联关系存在时

浅克隆只克隆外层类,关联类被克隆的是地址

深克隆是将关联类也进行克隆

在这里插入图片描述

在这里插入图片描述

package com.igeek.javase.ch06.object.clone;
public class Person implements Cloneable{
    

    private String name;
    private String gender;
    private int age;

    //一对一关联
    private Phone phone;

    //重写克隆方法 Ctrl+O
    @Override
    protected Person clone() throws CloneNotSupportedException {
    
        //浅克隆
        //Person person = (Person)super.clone();
        //return person;

        //深克隆
        Person person = (Person)super.clone();
        Phone phone = this.phone.clone();
        person.setPhone(phone);
        return person;
    }

    public Person() {
    
    }

    public Person(String name, String gender, int age, Phone phone) {
    
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.phone = phone;
    }

    /** * 获取 * @return name */
    public String getName() {
    
        return name;
    }

    /** * 设置 * @param name */
    public void setName(String name) {
    
        this.name = name;
    }

    /** * 获取 * @return gender */
    public String getGender() {
    
        return gender;
    }

    /** * 设置 * @param gender */
    public void setGender(String gender) {
    
        this.gender = gender;
    }

    /** * 获取 * @return age */
    public int getAge() {
    
        return age;
    }

    /** * 设置 * @param age */
    public void setAge(int age) {
    
        this.age = age;
    }

    /** * 获取 * @return phone */
    public Phone getPhone() {
    
        return phone;
    }

    /** * 设置 * @param phone */
    public void setPhone(Phone phone) {
    
        this.phone = phone;
    }

    public String toString() {
    
        return "Person{name = " + name + ", gender = " + gender + ", age = " + age + ", phone = " + phone + "}";
    }
}


package com.igeek.javase.ch06.object.clone;
public class Phone implements Cloneable {
    

    private String label;
    private double price;

    //重写克隆方法
    @Override
    protected Phone clone() throws CloneNotSupportedException {
    
        return (Phone)super.clone();
    }

    public Phone() {
    
    }

    public Phone(String label, double price) {
    
        this.label = label;
        this.price = price;
    }

    /** * 获取 * @return label */
    public String getLabel() {
    
        return label;
    }

    /** * 设置 * @param label */
    public void setLabel(String label) {
    
        this.label = label;
    }

    /** * 获取 * @return price */
    public double getPrice() {
    
        return price;
    }

    /** * 设置 * @param price */
    public void setPrice(double price) {
    
        this.price = price;
    }

    public String toString() {
    
        return "Phone{label = " + label + ", price = " + price + "}";
    }
}



package com.igeek.javase.ch06.object.clone;
public class PersonTest {
    

    public static void main(String[] args) throws CloneNotSupportedException {
    
        Phone phone = new Phone("华为",6000.0);
        Person p1 = new Person("张三","男",20, phone);
        Person p2 = p1.clone();

        System.out.println("---------------浅克隆----------------");
        System.out.println("----------克隆后,修改前--------");
        System.out.println("p1 = "+p1);  //张三 男 20 华为 6000.0
        System.out.println("p2 = "+p2);  //张三 男 20 华为 6000.0

        System.out.println("----------克隆后,修改后--------");
        p1.setGender("女");
        p1.getPhone().setLabel("苹果");
        System.out.println("p1 = "+p1);  //张三 女 20 苹果 6000.0
        System.out.println("p2 = "+p2);  //张三 男 20 苹果 6000.0

        System.out.println("---------------深克隆----------------");
        Phone phone2 = new Phone("华为",6000.0);
        Person p3 = new Person("张三","男",20, phone2);
        Person p4 = p3.clone();
        System.out.println("----------克隆后,修改前--------");
        System.out.println("p3 = "+p3);  //张三 男 20 华为 6000.0
        System.out.println("p4 = "+p4);  //张三 男 20 华为 6000.0

        System.out.println("----------克隆后,修改后--------");
        p3.setGender("女");
        p3.getPhone().setLabel("苹果");
        System.out.println("p3 = "+p3);  //张三 女 20 苹果 6000.0
        System.out.println("p4 = "+p4);  //张三 男 20 华为 6000.0
    }

}


第2章 Objects类

Objects类是对象工具类,它里面的的方法都是用来操作对象的。

2.1 equals方法

在刚才IDEA自动重写equals代码中,使用到了java.util.Objects类,那么这个类是什么呢?

JDK7添加了一个Objects工具类,它提供了一些方法来操作对象,它由一些静态的实用方法组成,这些方法是null-save(空指针安全的)或null-tolerant(容忍空指针的),用于计算对象的hashcode、返回对象的字符串表示形式、比较两个对象。

在比较两个对象的时候,Object的equals方法容易抛出空指针异常,而Objects类中的equals方法就优化了这个问题。方法如下:

  • public static boolean equals(Object a, Object b):判断两个对象是否相等。

我们可以查看一下源码,学习一下:

public static boolean equals(Object a, Object b) {
      
    return (a == b) || (a != null && a.equals(b));  


2.2 isNull

static boolean isNull(Object obj) 判断对象是否为null,如果为null返回true。

Student s1 = null;
Student s2 = new Student("蔡徐坤", 22);

// static boolean isNull(Object obj) 判断对象是否为null,如果为null返回true
System.out.println(Objects.isNull(s1)); // true
System.out.println(Objects.isNull(s2)); // false

第3章:补充 equals方法和hashCode方法

源码:

 @HotSpotIntrinsicCandidate
    public native int hashCode();

ps : native关键字是 java 语言和其他语言的交互的信号,即该功能使用了其他语言实现

hashCode()是一种算法,根据hash值将相同hash值得元素划分在一块区域,类似下图的哈希桶,

当两个对象的equals(Object中未被子类重写的)结果相同时,他们的哈希值一定相同,但是hash值相同,equals

不一定相同,可以是一个桶中的不同元素

在开发中我们经常会重写equals()方法,建议这边也重写一下hashCode()方法

具体参考:

(PS:哈希算法是为了提高查查找效率)

在这里插入图片描述

版权声明
本文为[朝上]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_51051154/article/details/120186332

随机推荐