详解 方法的覆盖 —— toString() 与 equals()的覆盖

在学习本篇博文前,建议先学习完本人的博文——《详解 继承(上)—— 工具的抽象与分层》
在本人之前的博文中曾讲过“基类”的知识,那么,本篇博文中的主题——Object类 和 基类的知识就密切相关了,那么,我们就直接进入主题吧。

Object类 是JAVA所提供的一个类类型,且是 所有类的基类

因为所有类继承于 Object类,所以,Object类的方法 自然而言就成为 其他类的方法。

而在特殊情况下,子类继承父类时,对于父类的方法的实现过程可能不太满意。
为了处理这种情况,Java也提供了一个机制——覆盖(或者叫做“方法重写”)

一般我们称其为“覆盖”,因为“覆盖”相对而言比较具体形象,而“方法重写” 容易和 本人之前博文中所讲解的 “方法重载”混淆。

下面我们来验证一下上述结论:
在这里插入图片描述由上图可知:我们并没有建立Object类,但是我们却可以调用它的方法,而且它提供了很多方法。

那么,本人在这里来讲解一下有关“覆盖”的 注意事项

注意事项:

  1. 父类中私有方法不能被重写
    因为父类私有方法子类根本就无法继承
  2. 子类重写父类方法时,访问权限不能更低, 最好就一致
  3. 父类静态方法,子类也必须通过静态方法进行重写

我们这篇博文中就主要讲解 Object类 中的 equals()方法toString()方法 的覆盖:

toString()方法 的覆盖:

首先,本人来介绍一下这个方法的用途吧:

用途:

  • 若我们部队这个方法进行重写(覆盖),则返回值为:包名称.类名称@这个对象的首地址
  • 一般我们根据目标对象的类的成员去重写这个方法,以便我们能够得到这个对象的各成员的值

本人用一段代码 和 它的运行结果 来展示一下toString()方法:
还是用我们上一篇博文中的类,来看看这个函数的返回值:
(这里任何类都可以,本人为了缩短读者们的阅读量,所以调用上篇博文的类)

package com.mec.about_override.demo;

public class Demo {

	public static void main(String[] args) {
		Animal animal =new Animal("动物");
		System.out.println(animal);
	}
	
	
}

在这里插入图片描述由上图可以看出:
而且,在一个类的对象 被输出 或者 转换为 String类型时,JVM自动调用toString()方法。
toString()方法的参数是 “一个类的对象”;
返回值是 “包名称.类名称@这个对象的首地址” 。

现在,本人来编写两个类,并且使其中一个类继承另一个类
在子类中对 toString()方法 进行覆盖:
Animal.java:

package com.mec.about_override.demo;

public class Animal {
	private String name;
	
	public Animal(String name) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public void cry() {
		System.out.println("动物的叫声!");
	}
	
}

Dog.java:

package com.mec.about_override.demo;

public class Dog extends Animal {
	public Dog(String name) {
		super(name);
	}
	
	public void cry() {
		System.out.println("汪汪");
	}
	
	public void dogAction() {
		System.out.println("狗子快跑!");
	}
	
	@Override
	public String toString() {
		return "我是" + getName();
	}
	
}

Demo.java:

package com.mec.about_override.demo;

public class Demo {

	public static void main(String[] args) {
		Dog dog = new Dog("二愣子");
		System.out.println(dog);
	}
	
}

在这里插入图片描述对比 上图 和 代码改动之前的测试结果,可以清晰地看到,toString()方法 被我们根据我们的用途覆盖了!

equals()方法 的覆盖:

首先,本人先来介绍一下这个方法的主要用途:

用途:

  • 若我们不对这个方法覆盖,调用时将比较两个对象的地址值:
    若相同,则返回true;反之,则返回false
  • 一般我们根据这两个对象的类的成员去重写这个方法,以便比较这两个对象的各成员的值是否相同

那么,本人用一段代码 和 它的运行结果 来展示一下equals()方法:
MecPoint.java:

package com.mec.about_equals.core;

public class MecPoint {	

	private int row;	//private表示这个变量只能在该类中被调用。用于防止外类修改该成员
	private int col;

	public final int MIN_ROW = 1;
	public final int MAX_ROW = 25;
	public final int DEFAULT_ROW = 12;
	public final int MIN_COL = 1;
	public final int MAX_COL = 80;		//屏幕点坐标范围:共25行、80列
	public final int DEFAULT_COL = 40;  //默认屏幕点坐标错误时,设为中值	

	public MecPoint() {
		setRow(0);
		setCol(0);
	}

	public MecPoint(int x, int y) {
		setRow(x);
		setCol(y);
	}

	public MecPoint(int x) {	
		setRow(x);
		setCol(0);
	}

	public MecPoint(MecPoint point) {
		setRow(point.row);
		setCol(point.col);
	}
	
	public void setPoint(int x, int y) {
		setRow(x);
		setCol(y);
	}

	public void setPoint(int x) {
		setPoint(x, 0);
	}

	public void setPoint(MecPoint source) {
		setPoint(source.row, source.col);
	}

	public void setRow(int x) {
		if(x <= MIN_ROW || x > MAX_ROW) {	//对x范围进行约束
			x = DEFAULT_ROW;
		}
		row = x;
	} 

	public int getRow() {
		return row;
	}
	
	public void setCol(int y) {
		if(y <= MIN_COL || y > MAX_COL) {	//对y范围进行约束
			y = DEFAULT_COL;
		}
		col = y;
	}

	public int getCol() {
		return col;
	}

	public void printPoint() {
		System.out.println("(" + row + "," + col +")");
	}
	
	@Override
	public String toString() {
		return "(" + row + "," + col + ")";
	}
	
}

Test.java:

package com.mec.about_equals.core;

public class Test {

	public static void main(String[] args) {
		MecPoint pointOne = new MecPoint(3,4);
		MecPoint pointTwo = new MecPoint(3,4);
		
		System.out.println(pointOne);
		System.out.println(pointTwo);
		
		System.out.println(pointOne == pointTwo);
	}

}

现在,我们来看看运行结果:
在这里插入图片描述
可以看到的是,最后一句的输出是 false
我们明明给两个对象的成员赋的值是一样的,为什么还是false呢?
这样的结果并不奇怪,因为JAVA对于类对象的 == 比较,是对其首地址的比较,而那两个变量占用的是不同的空间,所以无论如何,结果都是false。

现在就是来介绍 equals()方法 的时候啦,现在,我们来给 Test.java 增加一行代码,看看运行结果:
在这里插入图片描述
哦吼,结果还是false,难道我介绍错了吗?
知道本人一贯作风的同学知道,本人现在在“故弄玄虚”。
没错,这个方法并没有错,但是,这个函数是 Object类 提供的,MecPoint类 只是继承这个方法而已,这个方法并不会自动实现对 row 和 col 成员的比较。

本人先来介绍一个关键字——instanceof:

instanceof关键字 ;
(1)左边是一个对象,右边是一个类名称;
(2)这个对象必须是 这个类 或者 这个类的子类;
(若不满足这一点,则编译不通过,无法运行)
(3)若 左边的对象 是 右边的类 或者 这个类的子类,则返回 true,
若 右边的类是 左边的对象的类 或者 这个对象的类的子类,则返回 false。

好了,我们现在来处理一下之前的问题:
我们在MecPoint.java中加入以下代码:

	@Override
	public boolean equals(Object obj) {
		if(null == obj) {
			return false;
		}
		if(this == obj) {
			return true;
		}
		if(!(obj instanceof MecPoint)) {
			return false;
		}
		MecPoint otherPoint = (MecPoint) obj;
		return this.row == otherPoint.row
				&& this.col == otherPoint.col;
	}

在这里插入图片描述
但是,在这里本人还要提出的一点,就是:我们在未来编写代码时,若是想要 覆盖equals()方法,一般都会先覆盖hashcode(),关于这个操作的原因,请观看以下博文:
《覆盖equals时总要覆盖hashCode》
(至于这个知识点,我们可以先不深入了解,但是,养成良好的代码规范,在未来的工作中是很重要的!)

最后,要注意的是:
基类的用 final 修饰的方法,不能再子类中被覆盖。

posted @ 2020-03-04 21:45  在下右转,有何贵干  阅读(909)  评论(0编辑  收藏  举报