面向对象程序设计语言有三大特性:封装、继承和多态性。继承是面向对象语言的重要特征之一,没有继承的语言只能被称作“使用对象的语言”。继承是非常简单而强大的设计思想,它提供了我们代码重用和程序组织的有力工具。
类是规则,用来制造对象的规则。我们不断地定义类,用定义的类制造一些对象。类定义了对象的属性和行为,就像图纸决定了房子要盖成什么样子。
一张图纸可以盖很多房子,它们都是相同的房子,但是坐落在不同的地方,会有不同的人住在里面。假如现在我们想盖一座新房子,和以前盖的房子很相似,但是稍微有点不同。任何一个建筑师都会拿以前盖的房子的图纸来,稍加修改,成为一张新图纸,然后盖这座新房子。所以一旦我们有了一张设计良好的图纸,我们就可以基于这张图纸设计出很多相似但不完全相同的房子的图纸来。
基于已有的设计创造新的设计,就是面向对象程序设计中的继承。在继承中,新的类不是凭空产生的,而是基于一个已经存在的类而定义出来的。通过继承,新的类自动获得了基础类中所有的成员,包括成员变量和方法,包括各种访问属性的成员,无论是public还是private。当然,在这之后,程序员还可以加入自己的新的成员,包括变量和方法。显然,通过继承来定义新的类,远比从头开始写一个新的类要简单快捷和方便。继承是支持代码重用的重要手段之一。
类这个词有分类的意思,具有相似特性的东西可以归为一类。比如所有的鸟都有一些共同的特性:有翅膀、下蛋等等。鸟的一个子类,比如鸡,具有鸟的所有的特性,同时又有它自己的特性,比如飞不太高等等;而另外一种鸟类,比如鸵鸟,同样也具有鸟类的全部特性,但是又有它自己的明显不同于鸡的特性。
如果我们用程序设计的语言来描述这个鸡和鸵鸟的关系问题,首先有一个类叫做“鸟”,它具有一些成员变量和方法,从而阐述了鸟所应该具有的特征和行为。然后一个“鸡”类可以从这个“鸟”类派生出来,它同样也具有“鸟”类所有的成员变量和方法,然后再加上自己特有的成员变量和方法。无论是从“鸟”那里继承来的变量和方法,还是它自己加上的,都是它的变量和方法。
资料媒体库的设计
package dome;
import java.util.ArrayList;
public class Database {
private ArrayList<CD> listCD = new ArrayList<CD>();
private ArrayList<DVD> listDVD = new ArrayList<DVD>();
public void add(CD cd)
{
listCD.add(cd);
}
public void add(DVD dvd)//函数重载
{
listDVD.add(dvd);
}
public void list()
{
for( CD cd : listCD )
{
cd.print();
}
for( DVD dvd : listDVD )
{
dvd.print();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Database db = new Database();
db.add(new CD("abc", "abc", 4, 60, "..."));
db.add(new CD("def", "def", 4, 60, "..."));
db.add(new DVD("def", "def", 60, "..."));
db.list();
}
}
package dome;
public class CD {
private String title;
private String artist;
private int numofTracks;
private int playingTime;
private boolean gotIt = false;
private String comment;
public CD(String title, String artist, int numofTracks, int playingTime, String comment)
{
super();
this.title = title;
this.artist = artist;
this.numofTracks = numofTracks;
this.playingTime = playingTime;
this.comment = comment;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public void print() {
// TODO Auto-generated method stub
System.out.println( "CD:" + title + ":" + artist );
}
}
package dome;
public class DVD {
private String title;
private String director;
private int playingTime;
private boolean gotIt = false;
private String comment;
public DVD(String title, String director, int playingTime, String comment) {
super();
this.title = title;
this.director = director;
this.playingTime = playingTime;
this.comment = comment;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public void print() {
// TODO Auto-generated method stub
System.out.println( "DVD:" + title + ":" + director );
}
}
错误注意:类的静态成员函数只能访问类的静态数据成员,而不能访问类中的普通函数成员(非静态数据成员)
继承:
子类可以继承父类中的public、protected域,不能继承父类中的private域,但可以通过父类的public访问器访问其私有域。如果父类没有提供public的访问器,子类就不能访问父类的私有域。
package dome;
import java.util.ArrayList;
public class Database {
// private ArrayList<CD> listCD = new ArrayList<CD>();
// private ArrayList<DVD> listDVD = new ArrayList<DVD>();
private ArrayList<Item> listItem = new ArrayList<Item>();
// public void add(CD cd)
// {
// listCD.add(cd);
// }
//
// public void add(DVD dvd)//函数重载
// {
// listDVD.add(dvd);
// }
public void add( Item item )
{
listItem.add(item);
}
public void list()
{
// for( CD cd : listCD )
// {
// cd.print();
// }
//
// for( DVD dvd : listDVD )
// {
// dvd.print();
// }
for ( Item item : listItem )
{
item.print();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Database db = new Database();
db.add(new CD("abc", "abc", 4, 60, "..."));
db.add(new CD("def", "def", 4, 60, "..."));
db.add(new DVD("def", "def", 60, "..."));
db.list();
}
}
package dome;
public class CD extends Item{
private String title;
private String artist;
private int numofTracks;
private int playingTime;
private boolean gotIt = false;
private String comment;
public CD(String title, String artist, int numofTracks, int playingTime, String comment)
{
super();
this.title = title;
this.artist = artist;
this.numofTracks = numofTracks;
this.playingTime = playingTime;
this.comment = comment;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
CD cd = new CD("a", "b", 2, 2, "...");
cd.print(); //继承父类所有的东西
}
// public void print() {
// // TODO Auto-generated method stub
// System.out.println( "CD:" + title + ":" + artist );
// }
}
package dome;
public class DVD extends Item{ //CD成为Item的子类
private String title;
private String director;
private int playingTime;
private boolean gotIt = false;
private String comment;
public DVD(String title, String director, int playingTime, String comment) {
super();
this.title = title;
this.director = director;
this.playingTime = playingTime;
this.comment = comment;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
public void print() {
// TODO Auto-generated method stub
System.out.println( "DVD:" + title + ":" + director );
}
}
package dome;
public class Item {
public void print()
{
System.out.println( "Item" );
}
}
super() 只能在一个构造函数里调用一次;且必须在第一行
子类是从父类继承而来,继承了父类的属性和方法,如果在子类中先不完成父类的成员的初始化,则子类无法使用,因为在java中不允许调用没初始化的成员。在构造器中是顺序执行的,也就是说super()必须在第一行进行父类的初始化。
子类得到了父类所有的东西,子类拥有与父类相同的变量时,子类使用该变量时父类的同名变量被屏蔽,在父类函数中使用该变量就是父类自己的。两个同名变量没有任何联系。
package dome;
import java.util.ArrayList;
public class Database {
// private ArrayList<CD> listCD = new ArrayList<CD>();
// private ArrayList<DVD> listDVD = new ArrayList<DVD>();
private ArrayList<Item> listItem = new ArrayList<Item>();
// public void add(CD cd)
// {
// listCD.add(cd);
// }
//
// public void add(DVD dvd)//函数重载
// {
// listDVD.add(dvd);
// }
public void add( Item item )
{
listItem.add(item);
}
public void list()
{
// for( CD cd : listCD )
// {
// cd.print();
// }
//
// for( DVD dvd : listDVD )
// {
// dvd.print();
// }
for ( Item item : listItem )
{
item.print();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Database db = new Database();
db.add(new CD("abc", "abc", 4, 60, "..."));
db.add(new CD("def", "def", 4, 60, "..."));
db.add(new DVD("def", "def", 60, "..."));
db.list();
}
}
package dome;
public class CD extends Item{
// private String title;
private String artist;
private int numofTracks;
public CD(String title, String artist, int numofTracks, int playingTime, String comment)//构造函数
{
super(title, playingTime, false, comment);
//this.title = title;
this.artist = artist;
this.numofTracks = numofTracks;
// this.playingTime = playingTime;
// this.comment = comment;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
CD cd = new CD("a", "b", 2, 2, "...");//先做父类初始化 再做自己定义初始化 然后再进入构造函数
cd.print(); //继承父类所有的东西
}
// public void print() {
// // TODO Auto-generated method stub
// System.out.println( "CD:" + title + ":" + artist );
// }
}
package dome;
public class DVD extends Item{ //CD成为Item的子类
private String director;
public DVD(String title, String director, int playingTime, String comment) {
super(title, playingTime,false, comment);
this.director = director;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
DVD dvd = new DVD("a", "b", 1, "...");
dvd.print();
}
public void print() {
// TODO Auto-generated method stub
System.out.println( "DVD:");
super.print();//调用父类的print,不用super会调用自己的print
System.out.print(director);
}
}
package dome;
public class Item {
// protected String title; //protected: 自己可以访问 同一个包内其他子类可以访问
private String title;
private int playingTime;
private boolean gotIt = false;
private String comment;
public Item(String title)
{
super();
this.title = title;
}
public Item()
{
}
public Item(String title, int playingTime, boolean gotIt, String comment) {
super();
this.title = title;
this.playingTime = playingTime;
this.gotIt = gotIt;
this.comment = comment;
}
public void print()
{
System.out.print(title);
}
}
类定义了类型,DVD类所创建的对象的类型就是DVD。类可以有子类,所以由那些类定义的类型可以有子类型。在DoME的例子中,DVD类型就是Item类型的子类型。
子类型类似于类的层次,类型也构成了类型层次。子类所定义的类型是其超类的类型的子类型。
当把一个对象赋值给一个变量时,对象的类型必须与变量的类型相匹配,如:
Car myCar = new Car();
是一个有效的赋值,因为Car类型的对象被赋值给声明为保存Car类型对象的变量。但是由于引入 了继承,这里的类型规则就得叙述得更完整些:
一个变量可以保存其所声明的类型或该类型的任何子类型。
对象变量可以保存其声明的类型的对象,或该类型的任何子类型的对象。
Java中保存对象类型的变量是多态变量。“多态”这个术语(字面意思是许多形态)是指一个变量可以保存不同类型(即其声明的类型或任何子类型)的对象。
CD.print()覆盖了Item.print();