(四)Java关于继承extends

Java关于继承

继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。

关于继承我们先看看高手们是怎么理解的吧。

​ “面向对象的程序设计扩展了基于对象的程序设计,可以提供类型/子类型的关系。这是通过一种被称为继承(inheritance)的机制而获得的。子类不需要重新实现所有的特征,而是继承了其父类的数据成员和成员方法。Java通过一种被称为类派生的机制来支持继承。被继承的类称为基类(base class)或父类,而新的类被称为派生类(derived class)或子类。一般把基类和派生类实例的集合称作类继承层次结构。“

​ ——上文摘自《Java开发技术大全》(清华大学出版社) 刘新 等编著

上文可以看到“基类”、“派生类"等关键名词,也基本讲清楚了基类与派生类之间的基本关系——

​ 基类→派生→派生类,或者,派生类→继承于→基类。

extends 的意思是”拓展“。子类是父类的拓展。

类的继承关系:B属于A

面向对象程序攻计强调更“贴近人类思维习惯和模式”的思想。比如:学生→大学生→本科生。他们之间存在着“从属关系”。
从“外延"和"内涵"的角度考察可以发现:→左边的概念在外延上更大,内涵却相对简单;→右边的概念在内涵上更丰富,外延却相对更小。“本科生属于大学生”是两者最本质的关系。

“学生”是“大学生"的父类、基类;“大学生”是"学生”的子类、派生类;“大学生"是“本科生”的父类;“本科生”是“大学生”的子类。更细致地说,“大学生”具有“本科生”的所有属性和行为。

如果在建立了描述“大学生”的类之后可以发现,属于“本科生”的众多成员和方法都已经在“大学生"类中存在了,“本科生”类可以直接从“大学生"类中继承这些成员和方法,而不必重新编码。

这就是“代码复用”的直接体现,同时也是继承机制的终极目的之一!

子类会自动拥有父类部分或全部的属性和方法,同时可以继续定义子类自己的属性和方法,使得子类信息更详细、功能更明确。

继承中权限修饰符总结:

在这里插入图片描述

public和 private相对简单,是两个极端:从”保护“功能讲,public最弱,private最强;

protected 修饰的成员和方法,无论是否在同一个包下,子类都可以继承;且,同一包下的类,可以通过其对象引用。

无修饰的成员和方法,在同一包下的子类可以继承,不在同一包下的子类不能继承;且,不在同一包下的其非派生类,不能引用。

使用技巧:

**1、凡是打算为子类继承的成员和方法,用protected修饰;**

2、不打算被包外的类引用的成员和方法,不写任何修饰符;

无修饰的成员和方法,是为了打包后(*.jar文件)不被外面的类所引用。

关于super()

无论子类执行的构造方法是无参还是带参的,在默认情况下,JVM只调基类的无参构造方法!

那么,什么不是“默认情况”呢?

对了,就是用super (…)非常明确指明父类的具体哪一种构造方法!与 this()一样,super()也有两个严格的要求:

1、super只能出现在子类的方法或者构造方法中;

2、如果super()调用父类的构造方法,那它必须是构造方法的第一条语句!

3、super和 this 不能同时调用构造方法!

super VS this

1、代表的对象不同:

​ this:本身调用者这个对象;

​ super:代表对象的应用;

2、前提:

​ this:没有继承也可以使用;

​ super:只能在继承条件下才可以使用;

3、构造方法:

this():本类的构造;

​ super():父类的构造!

沿袭传统,还是锐意改革—成员、方法的覆盖

继承,可以使得子类拥有父类所拥有的成员与方法,子类也可以更改父类所提供的这些成员和方法,以适应子类不同于父类的环境和特殊要求。这使得工具不但能继承,还能“与时俱进",变化更新!

在面向对象程序设计中,上面思想的实现手段是:覆盖。

方法的覆盖一—主要的覆盖手段

方法的覆盖是对已有工具的改良、改革,是非常实用的技术手段。

首先对方法的覆盖进行语法和规则上的说明:

1、方法的覆盖只存在于有继承关系的类之间;

2、子类方法名称,参数个数和类型,必须与被覆盖的父类方法一致;

3、第2条成立,子类方法返回值类型必须与被覆盖的父类方法一致;

4、第2条成立,子类方法的修饰符不能“低于”被覆盖的分类方法;

5、违反第2项,其实质是实现了方法的重载,而非覆盖。

Java 继承实现 Animal 类
public class Animal {
	private String kind;
	
	public Animal() {}
	
	public Animal(String kind) {
		this.kind = kind;
	}

	public String getKind() {
		return kind;
	}

	public void setKind(String kind) {
		this.kind = kind;
	}

	public void cry() {
		System.out.println("动物的叫声!");
	}
}

Animal 类的意思就是”动物“,它有一个 kind 成员,并且不打算让这个成员被子类继承;但其Getter与Setter方法可以被继承,所以该被成员可以被子类间接继承。

public class Cat extends Animal{
	public Cat(String kind) {
		super(kind);
	}
	
	@Override
	public void cry() {
		System.out.println("小猫的叫声:喵喵喵~~~");
	}
}

Cat类从 Animal 类派生,其仅仅覆盖了 Animal 类的 cry()方法。

public class Dog extends Animal{
	public Dog(String kind) {
		super(kind);
	}

	@Override
	public void cry() {
		System.out.println("小狗的叫声:汪汪汪~~~");
	}
}

Dog 类与 Cat 类 类似;

关于 instanceof 是运算符,当然也是 Java 关键字。其直译过来就是”是实例否“。其作用是判别一个对象是否是某个类的对象。
System.out.println(cat instanceof Cat);
System.out.println(dog instanceof Dog);
System.out.println(animal instanceof Animal);

其输出都是true;

System.out.println(cat instanceof Animal);
System.out.println(dog instanceof Animal);

​ 其输出也都是true;

这说明,派生类的对象被看成基类的对象!

关于 多态

多态,即同一方法可以根据发送对象的不同而采用多种不同的行为方式。

多态存在的条件:

有继承关系;
子类重写父类方法;
父类引用指向子类对象;

注意:多态是方法的多态,属性没有多态性。

一切类的共同基类——Object

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

在这里插入图片描述

在上图中,我们看到了以前在其它类中看到的,不知道哪里来的方法。这是因为所有的类都继承于 Object 类。所以,Object 类的方法自然成为其他类的方法!这些方法很多都可以覆盖。

覆盖 toString() 方法

先看下面代码及其执行结果:

在这里插入图片描述

输出结果很奇怪:com.mec.polymorphic.core.Cat@1c4af82c

前面的是 cat 对象的类型,后面的是一串十六进制数字(其实就是cat对象所指向的实例的首地址),用@连接。这样的结果并不是我们想要的。这时候我们就需要通过覆盖 Object 类的 toString() 方法实现。

public class Cat extends Animal{
	public Cat(String kind) {
		super(kind);
	}
	
	public void cry() {
		System.out.println("小猫的叫声:喵喵喵~~~");
	}
	
	@Override
	public String toString() {
		return "我是" + getName();
	}
}

这次输出就是我们想要的了。

覆盖 equals() 方法

equals 的意思是“相等”,相等比较的意思。

众所周知,关于八大基本类型数值的大小比较,可以通过关系运算符,即 >、<、>=、<=、== 和 != 这些运算符进行。但是,复杂数据类型,而类的对象其本质是首地址,所以对于类对象的内容大小比较是不能用关系运算符的。

​ Object类定义的equals()和==的作用是相同的,比较俩地址值是否相同。

看下面代码:

public class Point {
	public static final int MIN_ROW = 1;
	public static final int MIN_COL = 1;
	public static final int MAX_ROW = 25;
	public static final int MAX_COL = 80;
	public static final int DEFAULT_ROW = 1;
	public static final int DEFAULT_COL = 1;
	
	private int row;
	private int col;

	public Point() {
		this(DEFAULT_ROW,DEFAULT_COL);
	}
	
	public Point(int row, int col) {
		setRow(row);
		setCol(col);
	}
	
	public Point(int row) {
		setRow(row);
		setCol(DEFAULT_COL);
	}
	

	
	public Point(Point point) {
		setRow(point.row);
		setCol(point.col);
	}
	
	public int getRow() {
		return row;
	}
	
	public void setRow(int row) {
		if (row < MIN_ROW || row > MAX_ROW) {
			row = DEFAULT_ROW;
		}
		this.row = row;
	}
	
	public int getCol() {
		return col;
	}
	
	public void setCol(int col) {
		if (col < MIN_COL || col > MAX_COL) {
			col = DEFAULT_COL;
		}	
		this.col = col;
	}
	
	@Override
	public String toString() {
		return "(" + row + "," + col "")";
	}
}

增加了toString() 方法的覆盖,下面是测试类:

public class Test {

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

输出为:

(4,2)
(4,2)
false

假如我们在最后紧接着输出一句:

System.out.println(pointOne.equals(pointTwo);

则输出结果依旧是:false

所以 Object 所提供的 equals() 方法比较的本质就是地址比较!

通常情况下我们自定义类如果使用 equals() 的话,也是比较“实体内容”,所以我们需要对equals()进行重写。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HB0o0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值