接上文:Java:继承
多态变量
我们定义了一个类出来,就是定义了一个新的类型,这个新的类型可以用来定义变量,可以制造类的对象存入定义的变量中(变量是管理者)。
类定义了类型,DVD类所创建的对象的类型就是DVD。类可以有子类,所以由那些类定义的类型可以有子类型。在下面的例子中,DVD类型就是Item类型的子类型。
**子类型类似于类的层次,类型也构成了类型层次。**子类所定义的类型是其超类的类型的子类型。
当把一个对象赋值给一个变量时,对象的类型必须与变量的类型相匹配,如:
Car myCar = new Car();
是一个有效的赋值,因为Car类型的对象被赋值给声明为保存Car类型对象的变量。但是由于引入 了继承,这里的类型规则就得叙述得更完整些:
一个变量可以保存其所声明的类型或该类型的任何子类型。
对象变量可以保存其声明的类型的对象,或该类型的任何子类型的对象。
Java中保存对象类型的变量是多态变量。“多态”这个术语(字面意思是许多形态)是指一个变量可以保存不同类型(即其声明的类型或任何子类型)的对象。
如下代码是一个媒体数据库雏形:
//Database.java
import java.util.ArrayList;
public class Database {
private ArrayList<item> listItem = new ArrayList<item>();
//listItem中可以存放许多不同的变量(对象),只要它们是该变量(item)类型的子类,就可以在容器中存放,
public void add(item item)
{
listItem.add(item);
}
public void list()
{
for(item item : listItem)
{
item.print(); //item会让实际管理的对象(动态类型)做它自己的print函数,
} //如果对应类没有print函数才会去调用item的print函数,这就是多态(覆盖)
}
//listItem的静态变量是item类型,里面的三个值的类型是CD、CD、DVD的(动态变量)
public static void main(String[] args) {
Database db = new Database(); //只要是item的子类就都可以放在里面
db.add(new CD("ab", "cd", 4, 60, "..."));
db.add(new CD("ef", "gh", 4, 60, "..."));
db.add(new DVD("hi", "jk", 60, "..."));
db.list();
}
}
//item.java
public class item {
private String title;
private int playingTime;
private boolean gotIt = false;
private String comment;
public item(String title, int playingTime, boolean gotIt, String comment) {
super();
this.title = title;
this.playingTime = playingTime;
this.gotIt = gotIt;
this.comment = comment;
}
public item()
{
}
public void print() {
System.out.println("item" + ":" + title);
}
public static void main(String[] args) {
}
}
//CD.java
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;
}
public static void main(String[] args) {
CD cd = new CD("a", "b", 2, 2, "...");
// cd.print();
}
public void print() {
System.out.println("CD:" + title + ":" + artist);
}
}
//DVD.java
public class DVD extends item{
private String title;
private String director;
private int playintTime;
private boolean gotIt = false;;
private String comment;
public DVD(String title, String director, int playintTime, String comment) {
this.title = title;
this.director = director;
this.playintTime = playintTime;
this.comment = comment;
}
public static void main(String[] args) {
DVD dvd = new DVD("abc", "a", 3, "...");
dvd.print();
}
public void print() {
System.out.println("DVD:" + title + ":" + director);
}
}
public static void main(String[] args) {
item item = new item("a", 0, true, "...");
// CD cd = item; //类型不匹配:不能从 item 转换为 CD
CD cd = new CD("a", "a", 0, 0, "...");
item = cd; //item = new CD("a", "a", 0, 0, "...");或item = (item)cd;
//这时item的动态类型是CD,静态类型是item,item被造型了
CD cc = (CD)item; //可以通过(CD)item的方式绕过子类禁止存储父类,但必须保证父类变量中的内容对子类来说是
//合法的,不然编译可以过,但在运行的时候会报错。(如果把itme = cd注释掉运行时就会报错)
}
“造型"不是"类型转换”
造型
静态类型是变量的声明类型,动态类型是变量中实际存储的值的类型。
让一个变量去管理动态类型和它的静态类型不符的类型,就叫做造型。
- Java的对象变量是多态的,它们能保存不止一种类型的对象
- 它们可以保存的是声明类型对象,或声明类型对象的子类
- 当把子类的对象赋给父类的变量的时候,就发生了向上造型
向上造型是把子类对象当作父类对象来用,向下造型是把父类对象当作子类对象来用(小心!)
向上造型:
- 拿一个子类的对象,当作父类的对象来用
- 向上造型是默认的,不需要运算符
- 向上造型总是安全的