基本概念
多态即指某一类事物存在多种形态。
多态在代码中的体现:父类或者接口的引用指向了其子类对象。
多态的好处:提高了代码的扩展性,前期定义的代码可以使用后期的内容。
多态的弊端:前期定义的内容不能使用(调用)后期子类的特有内容。要使用后期的特有内容,还得用子类的引用指向子类的内容。
多态的前提:1、必须有关系:继承、实现。2、要有覆盖。
转型:
向上转型:特有功能无法实现(限制),如果还想用特有功能,要向下转型。
向下转型:为了使用子类的特有方法。
注意:对于转型,自始至终都是子类对象在做着类型的变化。
类型判断:
instanceof:用于判断为对象的具体类型,只能用于引用数据类型判断。
增强了代码的健壮性,通常用于在向下转型前健壮性的判断。
代码示例1:
class Animal
{
abstract void eat();
}
class Dog extends Animal
{
void eat()
{
System.out.printlin("eat bone");
}
void housekeep()
{
System.out.printlin("housekeeping");
}
}
class Cat extends Animal
{
void eat()
{
System.out.printlin("eat fish");
}
void catchmouse()
{
System.out.printlin("catchmouseing");
}
}
class DuotaiDemo
{
public static void main(String[] args)
{
Animal a=new Cat();//自动类型提升,猫对象提升为动物类型。但是特有功能无法访问。
//作用就是限制对特有功能的访问,即向上转型
a.eat();
//如果想用具体动物猫的特有功能,可以将该对象进行向下转型
Cat c=(Cat)a;//向下转型的目的是为了使用子类的特有方法
c.eat();
c.catchmouse();
//注意:对于转型,自始至终都是子类对象在坐着类型的变化。把父类的对象转换为子类会发生异常,
//Animal a1=new Animal();假设Animal不是抽象类,可以创建对象
//把其他类的对象转换为本类对象也会类型转换异常
//Animal a1=new Dog();
//Cat c1=(Cat)a1;//ClassCastException类型转换异常
/* Cat c=new Cat();
Dog d=new Dog();
method(c);
method(d);
}
public static void method(Animal a)//Animal a=new Dog();多态的体现
//不能调用cathMouse()和housekeep等特有方法
{
a.eat();
} */
/*
类型判断
*/
public static void method(Animal a)
{
a.eat();
if(a instanceof Cat)//instanceof:用于判断为对象的具体类型,只能用于引用数据类型判断
{
Cat c=(Cat)a;
c.catchmouse();
}
else if(a instanceof Dog)
{
Dog d=(Dog)a;
d.housekeep();
}
}
}
代码示例2:
class Cat
{
void eat()
{
System.out.printlin("eat fish");
}
void catchmouse()
{
System.out.printlin("catchmouseing");
}
}
class BigCat extends Cat
{
void eat()
{
System.out.printlin("eat bigfish");
}
void sleep()
{
System.out.printlin("sleeping");
}
}
class DuotaiDemo2
{
public static void main(String[] args)
{
Cat x=new BigCat();
x.eat();//这时的结果是eat bigfish 因为eat方法在子类BigCat中被覆盖了
x.catchmouse()//这个调用是可以的,因为父类Cat中有这个方法
//为了调用sleep方法,向下转型:
BigCat y=(BigCat) x;
y.sleep();
}
}
多态的成员特点
成员变量
编译时:参考引用型变量所属的类中是否有调用的成员变量,有,编译通过,否则,编译失败
运行时:参考引用型变量所属的类中是否有调用的成员变量,并运行该所属类的成员变量。
简单说:编译和运行都参考等号的左边
成员函数(非静态)
编译时:参考引用型变量所属的类中是否有调用的成员函数,有,编译通过,否则,编译失败
运行时:参考对象所属的类中是否有调用的函数。
编译看左边,运行看右边
静态函数
编译时:参考引用型变量所属的类中是否有调用的静态函数。
运行时:参考引用型变量所属的类中是否有调用的静态函数。
简单说:编译和运行都看左边。
其实对于静态方法,是不需要对象的,直接用类名调用即可。
代码示例:
class Parent
{
//int num=3;
void show()
{
System.out.println("parent show");
}
static void method()
{
System.out.println("parent static method");
}
}
class Son extends parent
{
//int num=4;//父类有num这个变量,子类不需要定义这个变量,开发时一般不会有这个例子的情况,所以作为了解
void show()
{
System.out.println("son show");
}
static void method()
{
System.out.println("son staitc method");
}
}
class DuotaiDemo
{
public static void main(String[] args)
{
Parent p=new Son();//将子类型隐藏,就不能使用子类的特有方法
//System.out.println(p.num);//这时输出的是3,因为她已经向上转型为Parent.如果父类中没有num变量,则编译不通过
p.show();//输出:son show 覆盖操作 如果父类中没有show方法,则编译失败,因为p已经向上转型为Parent类了,不再是son类,而父类里没有这个方法
//非静态时调用依赖于对象,必须动态绑定在对象上
p.method(); //输出:parent static method
//静态函数存在于内存区里的静态区,不依赖于对象,依赖于引用
}
}