最近学的东西有点难,自己理解的慢一些,而且家里事情太多,所以写的有点迟,还是得慢慢打好基础^_^
中国大学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