Java面向对象程序设计(四)-- 继承与多态

本文介绍了如何使用Java面向对象编程(OOP)设计一个媒体资料库,包括使用继承减少代码冗余,以及如何利用多态性和覆盖提高代码灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近学的东西有点难,自己理解的慢一些,而且家里事情太多,所以写的有点迟,还是得慢慢打好基础^_^

中国大学MOOC传送门

-------------------------------------------------------------------------------------------------------------------------------------------------------------

如果我们想做一个媒体资料库,可以包含我们所拥有的CD以及DVD,那么我们可以这样来实现

package zhuanji;

import java.util.ArrayList;

public class database {
	private ArrayList<CD> cdlist = new ArrayList<CD>();
	private ArrayList<DVD> dvdlist = new ArrayList<DVD>();
	public void add(CD cd)
	{
		cdlist.add(cd);
	}
	public void add(DVD dvd)
	{
		dvdlist.add(dvd);
	}
	public void list()
	{
		for(CD cd:cdlist)
		{
			cd.print();
		}
		for(DVD dvd:dvdlist)
		{
			dvd.print();
		}
	}
	public static void main(String[] args) {
		database d = new database();
		d.add(new CD("Jay", "周杰伦",10,"2000","..." ));
		d.add(new CD("范特西", "周杰伦", 10,"2001","..." ));
		d.add(new CD("八度空间", "周杰伦", 10,"2002","..." ));
		d.add(new CD("叶惠美", "周杰伦", 10,"2003","..." ));
		d.add(new CD("七里香", "周杰伦", 10,"2004","..." ));
		d.add(new CD("十一月的肖邦", "周杰伦", 10,"2005","..." ));
		d.add(new CD("依然范特西", "周杰伦", 10,"2006","..." ));
		d.add(new CD("我很忙", "周杰伦", 10,"2007","..." ));
		d.add(new CD("魔杰座", "周杰伦", 10,"2008","..." ));
		d.add(new CD("跨时代", "周杰伦", 10,"2010","..." ));
		d.add(new CD("十二新作", "周杰伦", 10,"2012","..." ));//啊满满的周杰伦的回忆
		d.add(new DVD("不能说的秘密","周杰伦","2007","好看"));
		d.list();
	}

}
package zhuanji;

public class CD {
	private String title;
	private String artist;
	private int tracks;
	private String time;
	private boolean got = false;
	private String description;
	public CD(String title, String artist, int tracks, String time, String description) {
		super();
		this.title = title;
		this.artist = artist;
		this.tracks = tracks;
		this.time = time;
		this.description = description;
	}
	public static void main(String[] args) {
		
	}
	public void print() {
		System.out.println(artist+" : "+"《"+title+"》");		
	}

}
package zhuanji;

public class DVD {
	private String title;
	private String director;
	private String time;
	private boolean got = false;
	private String description;
	public DVD(String title, String director, String time, String description) {
		super();
		this.title = title;
		this.director = director;
		this.time = time;
		this.description = description;
	}
	public static void main(String[] args) {
		

	}
	public void print()
	{
		System.out.println(director + " : " + title);
	}

}

不过这样会显得比较臃肿,代码重复,CD和DVD可不可以通过一个模子来刻出来呢?于是就有了继承的概念。

一、继承

面向对象程序设计(OOP)有三大特性:封装,继承和多态性。继承是支持代码重用的一种有效手段。

基于已有的设计创造新的设计,就是继承。

我们把用来做基础派生其它类的那个类叫做父类、超类或者基类,

而派生出来的新类叫做子类。Java用关键字extends表示这种继承/派生关系。

通过继承,子类获得了父类中所有的成员,包括成员变量和方法除了构造方法

在此之外,子类中还可以加入新的成员,变量和方法。

public class CD extends Item{
	

}

Java的继承只允许单继承。

不过,不是所有情况下子类都能直接访问父类中的成员,具体看下表

父类成员访问属性在父类中的含义在子类中的含义
public对所有人开放可以直接访问
protected只有包内其他类,自己和子类可以访问可以直接访问
只有包内其他类可以访问

如果子类和父类在一个包内则可以直接访问,

否则不可以

private只有自己可以访问不可以直接访问

在构造一个子类的对象时,父类的构造方法也是会被调用的,而且父类的构造方法在子类的构造方法之前被调用

在程序运行过程中,子类对象的一部分空间存放的是父类对象。

因为子类从父类中得到继承,在子类对象的初始化过程中可能会用到父类中的成员。

所以初始化的时候先初始化父类的空间,然后子类的空间才得到初始化。

当我们去构造一个子类的对象的时候, 得保证他的父类的成员变量得到恰当的初始化(定义初始化和构造器)。

看看CD类的下面这部分代码

public CD(String title, String artist, int tracks, String time, String description) {
		super(title);
//		this.title = title;
		this.artist = artist;
		this.tracks = tracks;
		this.time = time;
		this.description = description;
	}

super 是 Java的一个关键字, 它用于限定该对象调用它从父类继承得到的实例变量或方法。

如果在构造器中使用 super 

那么 super 用于限定该构造器初始化的是该对象从父类继承得到的实例变量, 而不是该类自己定义的实例变量。

子类不会获得父类的构造器,但子类构造器里可以调用父类构造器的初始化代码。
子类构造器中调用父类构造器使用 super 调用来完成。

在一个构造器里只能调用一次super();且必须在构造函数内的第一行

如果子类和父类出现同名的成员变量的时候 ,因为计算机有就近原则(自己瞎编的)。

所以在子类中所指的变量就是子类的,在父类所指的变量就是父类的,他们之间没有任何联系。

所以在debug的时候我们可以看到子类的对象可以有两个同名的Element在窗口中,其实就是一个是子类的,一个是父类的,互不影响。

经过继承改良之后的媒体库代码如下:

package zhuanji;

import java.util.ArrayList;

public class database {
	private ArrayList<Item> itemlist = new ArrayList<Item>();//只需要一个ArrayList就好
	
	public void add(Item item)
	{
		itemlist.add(item);
	}
	public void list()
	{
		for(Item item:itemlist)//简化
		{
			item.print();//视item的具体类型而定,如果是CD则step into CD的print()函数,DVD同理
		}
	}
	public static void main(String[] args) {
		database d = new database();
		d.add(new CD("Jay", "周杰伦",10,"2000","..." ));
		d.add(new CD("范特西", "周杰伦", 10,"2001","..." ));
		d.add(new CD("八度空间", "周杰伦", 10,"2002","..." ));
		d.add(new CD("叶惠美", "周杰伦", 10,"2003","..." ));
		d.add(new CD("七里香", "周杰伦", 10,"2004","..." ));
		d.add(new CD("十一月的肖邦", "周杰伦", 10,"2005","..." ));
		d.add(new CD("依然范特西", "周杰伦", 10,"2006","..." ));
		d.add(new CD("我很忙", "周杰伦", 10,"2007","..." ));
		d.add(new CD("魔杰座", "周杰伦", 10,"2008","..." ));
		d.add(new CD("跨时代", "周杰伦", 10,"2010","..." ));
		d.add(new CD("十二新作", "周杰伦", 10,"2012","..." ));//啊满满的周杰伦的回忆
		d.add(new DVD("不能说的秘密","周杰伦","2007","好看"));
		d.list();
	}

}
package zhuanji;

public class CD extends Item{
	private String artist;
	private int tracks;
	
	public CD(String title, String artist, int tracks, String time, String description) {
		super(title,time,false,description);//把这四个变量传给父类的构造器
		this.artist = artist;
		this.tracks = tracks;//自己的变量当然还是自己赋值咯
	}
	public static void main(String[] args) {
		
	}
	public void print()
	{
		System.out.print(artist + " : ");
		super.print();//title是父类的,所以要调用父类的函数输出title
	}

}
package zhuanji;

public class DVD extends Item{
	private String director;
	
	public DVD(String title, String director, String time, String description) {
		super(title,time,false,description);
		this.director = director;
	}
	
	public static void main(String[] args) {

	}
	
	public void print()
	{
		System.out.print(director + " : ");
		super.print();
	}
}

 

package zhuanji;

public class Item {
	private String title;
	private String time;
	private boolean got;
	private String description;

	public Item(String title, String time, boolean got, String description) {
		super();//接收到那四个变量啦!
		this.title = title;
		this.time = time;
		this.got = got;
		this.description = description;//愉快的赋值
	}
	void print()
	{
		System.out.println(title);
	}
}

 二、多态

子类与父类之间的关系也体现了一种子类型的关系

子类的对象可以被当做父类的对象来使用:

子类的对象可以

1、赋值给父类的变量(Item item = new CD())

2、传递给需要父类对象的函数(new CD可以传给add函数的Item类型item)

3、放进存放父类对象的容器里(CD对象可以放在元素类型为Item的ArrayList中)

 

下面是三句重要的话:

 1、Java中的对象变量是多态的,他们能保存不止一种类型变量。

2、他们可以保存的对象类型是声明对象以及其子类型。

3、 当把子类的对象赋给父类的变量的时候,就发生了向上造型。

 

 一个有意思的定义:造型,英文Cast

造型:子类的对象可以赋给父类的变量(Java中不存在对象对对象的赋值)

不能把父类的对象赋给子类的变量

向上造型:拿一个子类的对象,当做父类的对象来用(由子到父就是向上)

向上造型是默认的,不需要运算符 

向上造型总是安全的

其实向上造型就是酱紫的

Item item = new Item("Jay", "2000",true,"...");
CD cd = new CD("范特西", "周杰伦", 10,"2001","..." );
item = (Item)cd;//把CD类型造型为Item类型然后赋给父类的变量

 函数调用的绑定:

当通过对象变量调用函数的时候,调用哪个函数这件事情叫做绑定

静态绑定:根据对象的声明类型来决定

动态绑定:根据变量的动态类型来决定

在Java中运行的时候,默认认为是动态绑定

在成员函数中调用其他成员函数也是一种动态绑定。

 覆盖(override):

子类和父类中存在名称和参数表完全相同的函数,这一对函数构成覆盖关系。

通过父类的变量调用存在覆盖关系的函数时,会调用变量当时所属的类的函数。

三、类型系统 

Java中总是存在一种单根结构,不管是什么类,最终其实都是Object类的子类。

Object类相当是Java系统中的root。

继承Object类不需要写extends,因为是系统默认的。

Object类里的函数:

ToString();

equals();

 

@override    :重写函数

这一行的存在就是告诉编译器,下面这一行的函数,是一个覆盖了父类的函数,

其函数名和参数表以及访问属性必须与父类的这个函数相同。

 例如:

@Override
public String toString() //重写object类的toString函数
{
	return "CD [artist=" + artist + ", tracks=" + tracks + "]";
}
	
@Override
public boolean equals(Object arg0) //重写object类的equals函数
{
    CD cc = (CD)arg0;//造型
	return artist.equals(cc.artist);//我们认为只要艺术家相同,那么这两个对象就是相同的
}
public static void main(String[] args) {
	CD cd = new CD("Jay", "周杰伦",10,"2000","...");
	System.out.println(cd.toString());
	CD cd1 = new CD("Jay", "周杰伦",10,"2000","...");
	System.out.println(cd.equals(cd1));//true,如果我们不重写,那么结果是false
}

而且我们可以有更深的继承,在CD或DVD下面可以有更加细分的子类,而且并不会耗费很多工夫,所以类的设计很重要。

OK,继续forward

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值