java- 多态详细解释

多态: 指允许不同类的对象对同一消息做出不同的行为,即同一消息可以根据对象类型的不同而采取多种不同的行为方式, 实现多态的技术被称为动态绑定,指的是在执行期间,判断所引用对象的实际类型,让该对象根据自己的 实际类型 调用其相应的方法,

多态存在的三个必要条件:
第一: 要有继承,
第二: 要有重写,
第三: 父类的引用指向子类的对象

多态的实现方式:
第一: 接口实现
第二: 对继承自父类的方法进行重写
第三: 同一个类中的方法重载

多态的优势:

1)可替换性(substitutability):多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。
2)可扩充性(extensibility):多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。
3)接口性(interface-ability):多 态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。如图8.3 所示。图中超类Shape规定了两个实现多态的接口方法,computeArea()以及computeVolume()。子类,如Circle和 Sphere为了实现多态,完善或者覆盖这两个接口方法。
4)灵活性(flexibility):它在应用中体现了灵活多样的操作,提高了使用效率。
5)简化性(simplicity):多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

java在使用多态时注意的几点:
对继承自父类的方法进行重写
Java的这种机制遵循一个原则:当父类对象引用子类对象时,被引用子类对象的类型而不是引用的父类类型决定了调用谁的成员方法,但是这个被调用的方法必须是在父类中定义过的,也就是说被子类覆盖的方法。

class A{
   public void sing(){
   }
}
class B extends A{
   public void sing(){}
   public void jump(){}
}

A s=new A();
A a=new B();
a.sing()// 根据实际的类型决定调用谁的方法,调用的是子类B的sing()方法
//  a.jump(); // 是错误的使用,因为 a是父类的指针,只能调用已经在父类定义过的方法,而 jump是子类特有的方法。

// 如果想要调用子类的新的方法,强制转换,从父类转换为子类,只能将其强制类型转换,但是一般从子类到父类,不需要强制转换, 但是如果s的实际类型是一个父类,强制转换为子类,会报错,抛出异常
        B b=(B) a;
        b.jump();
        // B bb=(B) s; // 错误的

在同一个类中重载实现
这里要再强调一下重载和重写的区别,
重载:是在一个类中,两个方法的方法名相同,但是参数的个数和参数的类型不同,注意的是返回值的类型不作为是否重载的一个判断条件
重写:是子类重写了父类中定义的方法,两个方法的方法名一致,参数个数和类型一致,返回值类型一致,意味着完全一样。


Compute com=new Compute();
int x=com.compute(1,2); //3
float y=com.compute(1.0,2.0); // 3.0

class Compute{
    public int compute(int x,int y){
        return x+y;
    }
    public double compute(double x, double y){
        return x+y;
    }
}

接口实现 ,
接口内只有方法声明,没有方法实现,接口不能被实例化,接口内的成员函数默认都是抽象成员函数,接口内的变量都为 Static final 类型的,
一旦一个类实现了这个接口,这个接口内的所有方法都必须要实现,即实现类中要重写该接口中的所定义的全部方法,否则程序报错,不被允

再介绍一下抽象类和接口的不同: 内部至少含有一个抽象方法的类,abstract修饰,其成员变量的类型没有限制,也可以存在非抽象方法,但是继承自抽象类的子类,其同样也必须实现其抽象方法。

        // 接口实现多态
        D dd=new DD();
        D ddd= new DDD();
        dd.eat();  // DD is eating
        dd.sleep(); //DD is sleeping
        ddd.eat(); //DDD is eating
        ddd.sleep(); //DDD is sleeping

class DD implements D{
    public void sleep(){
        System.out.println("D is sleeping");
    }
    public void eat(){
        System.out.println("D is eating");
    }
}

class DDD implements D{
    public void sleep(){
        System.out.println("DDD is sleeping");
    }
    public void eat(){
        System.out.println("DDD is eating");
    }
}
interface  D{
    public void sleep();
    public void eat();

}

实例分析:
这个题目考虑重载和重写还有继承关系,动态绑定的一个过程
一个类中如果定义了重载的方法,则系统在调用方法时,会根据参数的类型自动选择调用合适的方法
最核心的是这个调用的顺序:
方法调用的优先问题 ,优先级由高到低依次为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

class A
{
        public String show(D obj)...{
               return ("A and D");
        }
        public String show(A obj)...{
               return ("A and A");
        }
}
class B extends A
{
        public String show(B obj)...{
               return ("B and B");
        }
        public String show(A obj)...{
               return ("B and A");
        }
}
class C extends B{}
class D extends B{}
class E
{
      public static void main(String [] args)
     {
       A a1 = new A();
       A a2 = new B();
       B b = new B();
       C c = new C();
       D d = new D();
       // 前面这三个好理解, 首先a1是A类的引用,而且a1的实际类型也是A类,所以在进行show方法调用时,只能在A类的方法中寻找,
      // 我们都知道子类的对象都可以看做是父类类型的,因此第一句show(b)时,找不到参数类型为B的就会自动寻找参数类型为A的函数, 同理,下一句 先找参数为C类型的,找不到再找参数为B类型的,找不到再找参数为A类型的
       System.out.println(a1.show(b));   // A and A
       System.out.println(a1.show(c));   // A and A
       System.out.println(a1.show(d));   // A and D

       // 首先a2是A类的引用,而且a2的实际类型是B类,所以在进行show方法调用时,要在 A类 和 B类重写了A类的方法 中去寻找,具体使用哪个动态确定。
       System.out.println(a2.show(b));   // A and A 错 应该输出 B and A
       System.out.println(a2.show(c));   // A and A 错  应该输出 B and A
       System.out.println(a2.show(d));  //  A and D
       // b的引用是一个B类型的, b的实际类型也为B类型,但是B类型也可以看做是A类型的,所以寻找show()方法的时候要到A 和 B 的全部方法中去查询。
      // 如果在B的方法没有,但是A中寻找到参数类型完全相同的,则调用A中的方法,如果B中已经存在,则调用B中的方法优先调用,所以它的搜索顺序是这样的:比如b.show(d), 首先搜索B中有无参数类型为D的方法,没有,查看A中有无参数为D的方法,没有,查看B中有无C类型的方法,没有,查看A中有无C类型的方法。。。。。一直到根上的父类
       System.out.println(b.show(b));    // B and B
       System.out.println(b.show(c));    // B and B 
       System.out.println(b.show(d));    // B and B 错 应该为 A and D
      }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值