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

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

中国大学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

发布了99 篇原创文章 · 获赞 21 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43721423/article/details/96002037