对象的多态性
class 动物
{}
class 猫 extends 动物
{}
猫 x=new 猫();
动物 x=new 猫();一个对象,两种形态。
猫这类事物既具备猫的形态,又具备着动物的形态。这就是对象的多态性。
简单说:就是一个对象对应着不同类型
多态在代码中的体现
多态的好处:
提高了代码的扩展性,前期定义的代码可以使用后期的内容。
abstract class Animal {
abstract void eat();
}
class Dog extends Animal{
void eat(){
System.out.println("啃骨头");
}
void lookHome(){
System.out.println("看家");
}
}
class Cat extends Animal{
void eat(){
System.out.println("吃鱼");
}
void catchMouse(){
System.out.println("抓老鼠");
}
}
public class DuoTai {
public static void main(String[] args) {
Cat c=new Cat();
Dog d = new Dog();
// c.eat();
method(c);
method(d);
method(new Pig());
}
/*
public static void method(Cat c){
c.eat();
}
public static void method(Dog d){
d.eat();
}
*/
public static void method (Animal a){//Animal a=new Cat()(或者new Dog()),这就是多态的使用
a.eat();
}
}
//后期的内容
class Pig extends Animal{
void eat(){
System.out.println("饲料");
}
void catchMouse(){
System.out.println("拱白菜");
}
}
运行:多态的弊端:
前期定义的内容不能使用(调用)后期子类特有的内容。
public static void method (Animal a){//Animal a=new Cat()(或者new Dog()),这就是多态的使用
a.eat();
a.catchMouse();
}
运行出错!!!
使用多态的前提:
1 必须有关系,继承,实现。
2 要有覆盖
转型:
public static void main(String[] args) {
Animal a=new Dog();//自动类型提升,狗对象提升为动物类型。但是特有功能无法访问。
//作用就是限制对特有功能的访问。
//专业讲:向上转型。
a.eat()
//如果还想用具体动物猫的特有功能。
//你还可以将该对象进行向下转型。
Dog d=(Dog) a;//向下转型是为了使用子类中的特有方法。
d.eat();
d.lookHome();
//注意:对于转型,自始自终都是子类对象在做着变化
/*
Animal a1 =new Dog();
Cat c1=(Cat) a1; 这样转型是不行的,运行出错
*/
/*
Animal a =new Animal();
Cat c=(Cat) a; ClassCastException类型转换异常
*/
}
运行:类型判断:instanceof
用于判断对象的具体类型,且只能用于引用数据类型判断
为了增强代码的健壮性
public class DuoTai {
public static void method (Animal a){//Animal a=new Cat()(或者new Dog()),也就是说接受的可能是cat或者dog
a.eat();
Cat c= (Cat) a;
c.catchMouse();
}
public static void main(String[] args) {
method(new Cat());//可以运行
method(new Dog());//出错:ClassCastException
}
}
这时引入关键字instanceof,将method方法改为:
public static void method (Animal a){
if(a instanceof Cat){//instanceof用于判断对象的具体类型
//通常在向下转型前用于健壮性的判断
Cat c= (Cat) a;
c.catchMouse();
}else if(a instanceof Dog){
Dog d=(Dog) a;
d.lookHome();
}
}
调用:
public static void main(String[] args) {
method(new Cat());//可以运行
method(new Dog());//出错:ClassCastException
}
运行:多态时,成员的特点:
1 成员变量:
编译时:参考引用型变量所属的类中的是否有调用的成员变量,有,编译通过;没有,编译失败。
运行时:参考引用型变量所属的类中的是否有调用的成员变量,并运行该所属类中的成员变量。
简单说,编译和运行都参考等号的左边。(Fu f=new Zi(); Zi z=new Zi();都参考左边的类)
2 成员函数(非静态):
编译时:参考引用型变量所属的类中的是否有调用的成员变量,有,编译通过;没有,编译失败。
运行时:参考的是对象所属的类中是否有调用的函数
简单说:编译看左边,运行看右边
3 静态函数:
编译时:参考引用型变量所属的类中的是否有调用的静态方法
运行时:参考引用型变量所属的类中的是否有调用的静态方法
简单说,编译和运行都看左边。
其实对于静态方法,是不需要对象的。直接用类名调用
class Fu{
int num =3;
void show(){
System.out.println("Fu");
}
static void method(){
System.out.println("Fu static");
}
}
class Zi extends Fu{// 这种继承模式开发中基本不出现,可能会面试
int num=4;
void show(){
System.out.println("Zi");
}
static void method(){
System.out.println("Zi static");
}
}
public class DuotaiDemo {
public static void main(String[] args) {
Zi z=new Zi();
System.out.println(z.num);
//运行结果为 4
Fu f=new Zi();
System.out.println(f.num);
//运行结果为 3
f.show();//动态绑定到指定的对象上
//运行结果为Zi,
//若把Fu类中的show方法注释掉,则运行出错
//若把Zi类中的show方法注释掉,则运行结果为Fu
f.method();
//运行结果为Fu static 静态调用不需要创建对象
}
}
运行: