羿先生的学习笔记[1]: Java的“万类起源”——Object类

羿先生的学习笔记[1]:Java的“万类起源”——Object类

0. 序言

本系列博客用以记录本人在学习HIT-CS 软件构造课程中的一些收获,内容会涉及到课堂内容、感悟和本人关于Java语言的一些认识。

1. Object类简介

(1) Object类是Java默认提供的一个类,位于Java.lang包。Java.lang包中包含了Java最基础、最核心的类,无需通过import显式地导入即可使用。
(2) Object类是Java中所有类的父类。所有的类都继承自Object类。即如下两种写法:

public class Person {
    String name;
}

public class Person extends Object {
    String name;
}

是等价的。
也因此,任何一个对象都是Object类的一个实例。运行以下代码,

        Person tom = new Person();
        System.out.println(tom instanceof Object);

输出:

true

(3) Object类中包含了一些基本的方法。较为常用的经常需要覆写的方法有equals()方法、toString()方法、hashCode()方法等。

2. Object类中常用方法介绍

先定义一个Person类:

public class Person {
    String name;
    int age;
    Gender gender;

    public Person(String name, int age, Enum gender){
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
}
public enum Gender{
    MALE, FEMALE
}

equals()方法

执行如下代码:

	Person jimmy = new Person("Jimmy De Santa", 20, Gender.MALE);
	Person son_of_mike = new Person("Jimmy De Santa", 20, Gender.MALE);
	System.out.println(jimmy == son_of_mike);
	System.out.println(jimmy.equals(son_of_mike));

输出:

false
false

Java中使用 == 运算符比较两个对象,实质是比较两个对象的引用地址是否相等,这段代码中虽然两个对象的内容相同 (都是麦克的带孝子) ,但实际是在内存中申请了两个不同的空间来分别存储两个对象,因此使用 == 的判断结果为false。
而equals()方法判断结果为什么为false呢,Object.equals()方法定义如下:

    public boolean equals(Object obj) {
        return this == obj;
    }

我们在Person类中并没有覆写equals方法,因此实际上调用的是其父类Object中定义的equals方法,使用 == 运算符进行比较,因此结果为false。我们在Person类中覆写equals方法:

    @Override
    public boolean equals(Object obj){
        return obj instanceof Person && ((Person) obj).name.equals(name) &&
                ((Person) obj).age == age && ((Person) obj).gender == gender;
    }

并再次运行前述代码,结果为:

false
true

实现了对内容的实质性的比较。
简单总结:如果有比较对象实质性内容的需求,就要覆写equals方法。

toString()方法

toString方法通常被用来描述一个对象的基本信息。运行如下代码:

        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        System.out.println(set);

println方法会调用toString()方法,得到如下输出:

[1, 2, 3]

列出了集合中的元素。
如果我们不覆写toString方法,运行以下代码:

        Person jimmy = new Person("Jimmy De Santa",20, gender.MALE);
        Person tracey = new Person("Tracey De Santa",22, gender.FEMALE);
        System.out.println(jimmy);
        System.out.println(tracey);

得到结果

person.Person@16b98e56
person.Person@7ef20235

按照 包名.类名@地址 的格式输出
我们为了可以更直观地看到对象的信息,覆写toSring()方法

    @Override
    public String toString(){
        return "name:"+name+"\n"+"age:"+age+"\n"+gender;
    }

再次运行前述代码,结果为:

name:Jimmy De Santa
age:20
MALE
name:Tracey De Santa
age:22
FEMALE

总结:toString方法通常用来直观的显示对象的基本信息,在System.out.println()等方法中会被调用,一般需要覆写。

hashCode()方法

执行如下代码:

        Set<Person> DeSantas = new HashSet<>();
        Person jimmy = new Person("Jimmy De Santa",20, gender.MALE);
        Person son_of_mike = new Person("Jimmy De Santa",20, gender.MALE);
        System.out.println(DeSantas.add(jimmy));
        System.out.println(DeSantas.add(son_of_mike));
        System.out.println(DeSantas.size());

得到结果:

true
true
2

两个对象Jimmy和Mike的儿子虽然内容相同,使用equals方法比较的返回值也是true,但仍然成功地被放入了同一个集合De Santa一家中,显然不符合数学上集合的定义。尽管数学上要求集合中每个元素互不相等,但如果每新加入一个元素都要与集合中所有元素进行一次比较,效率将会十分低下。假如De Santa家族有1,000,000个人,新加入一名成员就要调用一百万次equals()方法。因此HashSet等工具实际上运用了散列表技术。每一个对象都有一个对应的hash code,也就是哈希值(散列值)。通过这种方法使其插入、查找、删除操作均为O(1)的时间复杂度。
我们覆写hashCode方法:

    @Override
    public int hashCode(){
        return name.hashCode();
    }

并再次运行前述代码,得到结果:

true
false
1

可见只有jimmy被存储到了集合中。
总结:如果需要将对象存储在HashSet、HashList等数据结构中,覆写hashCode()方法是必要的,且通常相同的对象应当具有相同的哈希值,不同的对象应有不同哈希值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值