多态是同一个行为具有多个不同表现形式或形态的能力。
实际开发中,多态的体现更多的是里氏代换原则&依赖倒置原则使用,即针对接口编程,依赖于抽象而不依赖具体,以及任何基类/父类可以出现的地方,子类一定可以出现。
java中多态的体现:
使用父类型引用指向子类对象;(使用接口类型引用指向实现类对象)
多态存在的三个必要条件
abstract class Animal
{
public abstract void eat();
public abstract void sleep();
}
class Dog extends Animal
{
public void eat(){
System.out.println("狗吃肉..");
}
public void sleep(){
System.out.println("狗zzZZ");
}
}
class Cat extends Animal
{
public void eat(){
System.out.println("猫吃鱼..");
}
public void sleep(){
System.out.println("猫zzZZ");
}
}
class TestPolymorphism1
{
public static void main(String[] args)
{
//Dog d = new Dog(); //本态引用
Animal a = new Dog(); //多态引用 --> 此处发生多态了
/*
多态的使用情况之非静态方法:
编译期(编译阶段):看左边(父类型)
运行期(运行阶段):看右边 --> 运行子类重写父类以后的内容
*/
a.eat();
a.sleep();
//调用检查狗的方法
//checkDog(d); //相当于:Dog d = d --> Dog d = new Dog() 本类引用
//调用检查动物的方法,目的为了检查一条狗
//checkAnimal(d);
//相当于:Animal a = d --> Animal a = new Dog() 多态引用
//checkAnimal(new Cat());
//此处发生了多态 Animal a = new Cat()
}
/*
如果有100种动物我都需要对其进行检查,是不是需要定义100个check方法;
这样做程序冗余度很高(阅读性很差),并且扩展性也不理想;
能不能一个check方法就解决检查100个动物的需求
*/
/*
以下这种多态的使用领域:
多态参数 √
多态数组
好处:
降低了程序代码的冗余度,提高了代码的阅读性;
并且此功能变的极具扩展性
*/
//检查动物
public static void checkAnimal(Animal a){
//检查项目:吃、睡
a.eat();
a.sleep();
}
/*
//检查狗
public static void checkDog(Dog d){
//检查项目:吃、睡
d.eat();
d.sleep();
}
//检查猫
public static void checkCat(Cat c){
//检查项目:吃、睡
c.eat();
c.sleep();
}
*/
}
多态数组举例:
/*
演示多态的使用领域之多态数组
好处:
降低了程序代码的冗余度,提高了代码的阅读性;
并且此功能变的极具扩展性
*/
//几何图形类
abstract class GrometricObject
{
abstract double findArea();
}
//圆
class Circle extends GrometricObject
{
private double radius; //半径
Circle(double radius){
this.radius = radius;
}
Circle(){
}
//重写父类GrometricObject中的抽象方法
double findArea(){
return Math.PI * radius * radius;
}
}
class Rectangle extends GrometricObject
{
private double length; //长度
private double width; //宽度
Rectangle(double length,double width){
this.length = length;
this.width = width;
}
Rectangle(){
}
//重写父类GrometricObject中的抽象方法
double findArea(){
return length * width;
}
}
class TestPolymorphism2
{
public static void main(String[] args)
{
Circle[] cirs = new Circle[4]; //定义圆数组,内部存储4个圆对象
Rectangle[] recs = new Rectangle[3]; //定义矩形数组,内部存储3个矩形对象
GrometricObject[] gos = new GrometricObject[7]; //定义几何图形数组,内部可以存储7个任意的几何图形
gos[0] = new Circle(1.0); //此处发生多态
gos[gos.length - 1] = new Rectangle(2.0,3.0); //此处发生多态
//遍历几何图形数组
for(int i = 0; i <= gos.length - 1;i++){
//System.out.println(gos[i].findArea());
System.out.println(gos[i]);
}
}
}
只能使用父类中已经定义的成员变量和函数,不能使用子类中独有的变量或函数;如果需要调用子类独有的成员,就需要先进行强转(向下转型);可能在运行的过程中会出现java.lang.ClassCastException异常
为了避免其发生,我们可以使用instanceof关键字
/*
演示多态的弊端:
强制向下转型可能出现java.lang.ClassCastException,
为了避免其出现,我们可以使用instanceof关键字来把控
格式:
需要被转换类型的对象 instanceof 需要转换成的类型
如果是,则返回true;
如果不是,返回false
*/
abstract class Person
{
abstract void eat();
abstract void walk();
}
class Man extends Person
{
//独有属性
boolean isSmoking;
void eat(){
System.out.println("大口吃肉,大碗喝酒");
}
void walk(){
System.out.println("大摇大摆的走路");
}
//独有方法
void entertainment(){
System.out.println("花天酒地!!");
}
}
class Woman extends Person
{
//独有属性
boolean isBeauty;
void eat(){
System.out.println("细嚼慢咽");
}
void walk(){
System.out.println("婀娜多姿的走路");
}
//独有方法
void shopping(){
System.out.println("买买买...");
}
}
class TestPolymorphism3
{
public static void main(String[] args)
{
//Person p = new Woman(); //此处发生多态 引用数据类型:小 -> 大 向上转型(造型)
/*
int i = 20;
short s = 200;
i = s; //基本数据类型:小 -> 大 自动类型转换
*/
//p.eat();
//p.walk();
/*
对于多态性 --> 非静态方法:
编译期看父类型,由于shopping()不存在于父类Person中,
所以编译出错
*/
//p.shopping();
/*
需求:
我需要在现有代码的基础上调用shopping(),该怎么做?
将p(Person类型) -> Woman类型就可以了
大 -> 小 向下转型(造型)
强制向下转型 --> 强制类型转换
格式:
需要被转换成的类型 引用名 = (需要被转换成的类型)变量名;
*/
//Woman w = (Woman)p;
//w.shopping();
/*
由于Man和Woman都是Person类型的子类型,所以w.shopping()代码没有问题;
但是运行的过程中报错了,
发生了:java.lang.ClassCastException --> Man cannot be cast to Woman
因为具体的对象是一个实实在在的Man对象,没有shopping方法
问题出现:
强制类型转换(向下转型)有风险,使用需谨慎!!
可以使用instanceof关键字来控制避免出现ClassCastException
格式:
需要被转换类型的对象 instanceof 需要转换成的类型
如果是,则返回true;
如果不是,返回false
*/
Person p1 = new Man(); //此处发生多态
//Woman w1 = (Woman)p1;
//w1.shopping();
test(p1);
test(new Woman()); //Person p = new Woman()
}
public static void test(Person p){
//判断
if(p instanceof Man){
Man m = (Man)p;
m.entertainment();
}else if(p instanceof Woman){
Woman w = (Woman)p;
w.shopping();
}
}
}
自动向上转型:
在使用多态时,将子类型对象赋值给父类型引用,相当于将对象的类型提升为父类型,叫做向上转型;因为这个过程可以自动进行,所以叫做自动向上转型;
如:
class Fu{}
class Zi extends Fu{}
Fu f = new Zi();//就是发生了自动向上转型
强制向下转型:
将父类型引用(对象)赋值给子类型引用,相当于将父类型向下转换成子类型,叫做向下转型;这个过程不能自动进行,需要强制进行,所以叫做强制向下转型;
如:
class Fu{}
class Zi extends Fu{}
Fu f = new Fu();
Zi z = (Zi)f;//这里将父类型引用转换为子类引用,发生了强制向下转型;
结论:使用强制向下转型,可以解决多态使用中的弊端;
结论:在强制向下转型前先使用instanceof关键字进行判断,可以避免出现类型转换异常;