继承
媒体资料库的设计
public class CD {
private String title;
private String artist;
private int numofTracks;
private int playingTime;
private boolean gotIt;
private String comment;
public CD(String title, String artist, int numofTracks, int playingTime, Stirng comment) {
super();
this.title = title;
this.artist = artist;
this.numofTracks = numofTracks;
this.playingTime = playingTime;
this.comment = comment;
}
public void print(){
System.out.println(title+":"+aritst);
......
}
}
public class DVD {
private String title;
private String director;
private int playingTime;
private boolean gotIt = false;
private String comment;
public CD(String title, String director, int playingTime, Stirng comment) {
super();
this.title = title;
this.director = director;
this.playingTime = playingTime;
this.comment = comment;
}
}
CD和DVD几乎一摸一样
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) {
listCD.add(cd);
}
public void list(){
for (CD cd : listCD) {
cd.print();
}
for (DVD dvd : listDVD) {
dvd.print();
}
}
}
在DataBase中的使用也一模一样,不同的只有一个是cd一个是dvd 在这两段代码中出现两大量的代码复制,是代码质量不良的一种表现,意味着将来维护这样的代码是不容易的(后期想修改print函数,每一个print都需要更改;不便于增加新的类)
修改方法:extend
建立一个Item类,CD是一种Item,DVD也是一种Item public class DVD extends Item public class CD extends Item 使得DVDheCD都是Item的子类
public class Item {
public void print() {
}
}
public class Database {
private ArrayList<Item> listItem = new ArrayList<item>();
public void add(Item item) {
listItem.add(item);
}
public void list(){
for (Item item : listItem) {
item.print();
}
}
public static void main(String[] args) {
DataBase db = new DataBase();
db.add(new CD("abc", "abc", 4, 60, "..."));
db.add(new CD("def", "def", 4, 60, "..."));
db.add(new DVD("xxx", "xxx", 4, 60, "..."));
db.list();
}
}
现在DataBase只认识Item这个类,它与CD和DVD没有直接联系了。 CD从Item中继承,cd得到Item中的所有。 父类有什么,子类天然有什么,在子类中都是可能可以用的(涉及到访问权限的问题)。除此之外子类还可以增加新的东西。
此时的继承还不是完美的,还需要继续修改
子类父类关系
目前的代码从DataBase角度看,是完美的,只有一个容器,一个add函数,一个list中的for循环。 但从DVD和CD中看仍存在相同的东西,这些相同的东西可以提取出来,放入Item中。
public class Item {
private String title;
public void print() {
}
}
当成员变量以private放入Item(父类)中,CD和DVD的构造函数会提示:“This field item.title is not visible”。 父类中private的东西只有父类自己可以用,子类无法使用(虽然子类继承得到了,但无法直接使用)。 这个问题有两个解决方案:
- 将private改为另外一个修饰符——protected(同一个包内可以访问,子类可以访问)
public class Item {
protected String title;
public void print() {
}
}
- 维持为private,不在子类中进行使用(该变量的初始化不放在子类中,在父类中进行初始化,子类中直接传入)
public class Item {
private String title;
private int playingTime;
private String comment;
public Item(String title) {
super();
this.title = title;
this.playingTime = playingTime;
this.comment = comment;
}
public void print() {
System.out.println("Item");
}
}
public class CD {
private String artist;
private int numofTracks;
private boolean gotIt = false;
public CD(String title, String artist, int numofTracks, int playingTime, Stirng comment) {
super(title, playingTime, comment);
this.artist = artist;
this.numofTracks = numofTracks;
}
没有super(),程序自动会去找父类中没有参数的构造器,父类中可以有很多构造器,只要参数不同就可以同时存在,子类中使用super会自动寻找父类中 合适的构造器
public class Item {
private String title;
public Item(){
}
public Item(String title) {
super();
this.title = title;
}
public void print() {
System.out.println(title);
}
}
DVD中也有title,从父类中同时继承了title;就近原则,离我最近的是自己的,此处DVD中构造器中的title是它自己的title,父类中的看不见。子类虽然不能直接使用父类中private的东西,但可以通过父类的函数调用来进行更改。 父子类中的同名变量没有任何关系。 若要使用父类中的成员函数,需要用到super去调用,比如这个print功能的完整实现,即需要用到子类中的print,也需要用到父类中的print
public class DVD {
private String title;
private String director;
private boolean gotIt = false;
private int playingTime;
private String comment;
public CD(String title, String director, int playingTime, Stirng comment) {
this.title = title;
this.director = director;
this.playingTime = playingTime;
this.comment = comment;
}
public void print() {
System.out.ptint("DVD:");
super.print();
System.out.print(director);
}
}
父类的定义、初始化先做,做完之后才轮到子类的定义、初始化
多态变量
- Java的对象变量是多态的,它们能保存不止一种类型的对象
- 它们可以保存的声明类型的对象,或声明类型的子类的对象
- 当把子类的对象赋给父类的变量的时候,就发生了向上造型
在DataBase中,我们给的都是Item的子类的某个对象
子类和子类型:
子类型与赋值:
子类的对象可以赋值给父类的变量
子类和参数传递:
子类的对象可以传递给需要父类对象的函数
子类型和容器:
子类的对象可以放在存放父类对象的容器里
向上造型
把一个类型的对象赋给另外一个类型的变量 造型cast 子类的对象可以赋值给父类的变量 注意:Java中不存在对象对对象的赋值 父类的对象不能赋值给子类的变量
Vechicle v;
Car c = new Car();
v = c;
c = v;
可以用造型: 只有当v这个变量实际管理的是Car才行
c = (Car) v;
造型:
- 用括号围起类型放在值的前面
- 对象本身并没有发生任何变化(所以不是“类型转换”)
- 运行时有机制来检查这样的转化是否合理
- ClassCastException
向上造型:
- 拿一个子类的对象,当作父类的对象来用
- 向上造型是默认的,不需要运算符
- 向上造型总是安全的
多态
此处的print,一个是声明类型,一个是动态类型,当调用时,会让实际管理的对象去做那个动作 函数调用的绑定:
覆盖override
- 子类和父类中存在名称和参数表完全相同的函数,这一对函数构成覆盖关系
- 通过父类的变量调用存在覆盖关系的函数时,会调用变量当时所管理的对象所属的类的函数
cd中的print就覆盖了item中的print,通过一个item的变量去调用print函数时,他会根据实际是哪一个类,来决定到底调用哪一个print函数
类型系统
OBJECT类
所有的类都是继承自Object的 Object类的函数:
不可以在自己构造的类中直接使用,需要override重载
DoMe的新媒体类型:可扩展性
很方便地添加新的类型,可拓展性好
|