Java 多态

多态:多态分为两种
(1)编译时多态:方法的重载
(2)运行时多态:Java虚拟机根据调用该方法实例的类型来决定选择调用哪个方法,被称为运行时多态,我们所说的多态是指运行时多态。

1、多态是OOP(面向对象编程)的三大特性之一(封装、继承、多态)。
所谓封装:就是指把现实需求中的事务抽象成一个对象,并且对自己的内部的域和方法不同情况具有不同的访问权限。隐藏类的内部实现机制,可以在不影响使用的情况下,改变类的内部结构(比如:增加方法),同时也可以保护数据。对外界而言它的内部细节是隐藏的,暴露给外界的只有它的访问方法。
继承:是指类具有继承父类的方法和域的能力,并可以根据需要扩展功能,从而具有一定的代码复用功能。同时也为多态做了铺垫。
多态:就是父类引用指向其任何一种子类,jvm根据不同的指向子类在运行时绑定对应的函数,从而调用相应类中的同名方法。

比如:A a=new B()  (B是A的子类,或者A是一个接口,B或它的一个父接口实现A)
在上面的代码中表示:赋值a一个B的实例,a的类型为A。这意味着不能在**B中**调用A中没有定义过的方法。但如果输出a.getClass().getName()的值,将会得到“B”而不是“A”。这是因为在编译时a的类型为A,因此编译器将不允许调用B中没有在A中定义的方法。另一方面,运行时a的类型为B,如a.getClass().getName()的值。
多态本质,如果B中覆盖了A中的方法play,那么调用a.play()将是调用B中的play;如果方法stop不是在B中实现,那么JVM足够智能根据继承结构去查找,然后参数集是否正确,从而在编译的时候检查是否正确。
package polymorphismandreflect;
class A {
    public void play(){
        System.out.println("I am a A");
    }
    public void stop(){
        System.out.println("I am stop A");
    }
}
class B extends A{
    public void play(){
        System.out.println("I am a B");
    }
public void voice(){
        System.out.println("I am a voice");
    }
}
public class testpolymorphism  {
 public void test(){
     System.out.println("I am a test");
 }
 public static void main(String[] args) {
    A a =new B();
    a.play();
    a.stop();
    //a.voice();
    //A test=new testpolymorphism();
    //test.test();
}
}

I am a B
I am stop A
从结果中可以看出在编译的时候,由于把a当做A类型,所以在test中a.voice();是不能调用的。即在继承子类中不能调用父类中没有的方法,在别的类中也不可以。但在运行时a是B类型,这种方法绑定是发生在运行时而不是编译时,区别于静态方法和final,静态方法就是在编译时把方法调用和方法体绑定在一起。
多态的好处是在比如做参数类型的时候,父类做参数,实际传值时可以使其任意子类。如object, 同时作为引用变量可以指向不同的对象。
进一步了解:
多态存在的三个必要条件:
继承
要有方法重写
父类引用指向子类对象(所以父类引用指向父类就不算多态了)

public class Letter {
   public static void main(String[] args) {
    A aa=new A();
    A ab=new B();
    B bb=new B();
    C c=new C();

    ab.show(bb);
    System.out.println(ab.getClass());
    ab.show(aa);
}
}
class A{
    public void show(A obj){
        System.out.println("A-A");
    }
//  public void show(B obj){如果不注释则会输出“B-B” 具体请看下面解析
//      System.out.println("A-B");
//  }
    public void show(C obj){
        System.out.println("A-C");
    }

}
class B extends A{
    public void show(B obj){
        System.out.println("B-B");
    }
    public void show(A obj){
        System.out.println("B-A");
    }

}
class C extends B{
    public void show(C obj){
        System.out.println("C-C");
    }
    public void sshow(C obj){
        System.out.println("CC");
    }
}

输出结果:

B-A
class polymorphism.B
B-A

对于第一条输出结果可能会有疑问:为什么不是“B-B”那?想知道请先理解下面这句话:
当超类(父类)对象引用变量引用子类对象时,决定调用哪个类的成员方法的是引用变量指向的对象的类型,而不是引用变量定义的类型,这种情况下,这个被调用的方法必须是在超类中定义过(即不能执行子类中独有的方法)。
当超类(父类)对象(A)引用变量(ab)引用子类对象(new B())时,决定调用哪个类的成员方法(show())的是引用变量指向的对象的类型(B),而不是引用变量定义的类型(A),这种情况下,这个被调用的方法必须是在超类中定义过(即不能执行子类中独有的方法)。
这个情况比较符合ab.show(aa);
虽然ab类型是A,但ab指向的类型是B,所以决定执行方法show()的是类型B,根据优先级执行顺序:this.show(o),super.show(o),this.show((super)o),super.show((super)o);
这里的this就是B对象(创建子类只会调用父类无参构造器来初始化父类非私有属性和方法,这样子类才会有父类的方法和属性,并不会创建父类对象)但在java编译的时候就认为是类型A,所以只能调用在A中定义的的方法和属性。所以当一个子类对象被实例化后,该实例对象会包含两部分:一部分是子类(B)中定义的属性和方法(包含重写父类中的方法),还会包含父类(A)中的属性和方法。由于会先去从父类中继承部分查找show(A obj),发现父类中定义了该方法,且B重写了该方法所以执行子类B中的方法输出B-A。
但对于ab.show(bb);根据顺序,先执行this.show(B obj),但是类B实例化对象继承父类方法中没有该方法ab.show(B obj);且没有超类 所以执行第三个向上转(this.show(super B))this.show(A obj)但这个却被子类B重写了 所以这个执行子类的方法show(A obj)。输出B-A

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java指的是同一个方法名可以根据不同的对象调用出不同的行为。具体来说,多是一种面向对象编程的特性,实现多的方式主要有两种:方法重载和方法覆盖。方法重载指的是在一个类中定义多个同名方法,但这些方法有不同的参数列表,编译器会根据参数列表的不同选择合适的方法进行调用。方法覆盖指的是子类重写父类的方法,使得在使用父类对象调用该方法时,实际调用的是子类中的方法。 多的好处在于,它可以提高代码的灵活性和可扩展性。通过多,我们可以为不同的对象提供不同的行为,从而使得程序更加具有扩展性。此外,多还可以让程序的调用更加简洁、清晰,提高了代码的可读性和可维护性。 下面是一个简单的Java的例子: ```Java class Animal { public void makeSound() { System.out.println("动物发出声音"); } } class Cat extends Animal { public void makeSound() { System.out.println("猫发出“喵喵”的声音"); } } class Dog extends Animal { public void makeSound() { System.out.println("狗发出“汪汪”的声音"); } } public class PolymorphismExample { public static void main(String[] args) { Animal animal1 = new Animal(); Animal animal2 = new Cat(); Animal animal3 = new Dog(); animal1.makeSound(); // 动物发出声音 animal2.makeSound(); // 猫发出“喵喵”的声音 animal3.makeSound(); // 狗发出“汪汪”的声音 } } ``` 在上面的例子中,Animal是一个父类,Cat和Dog是Animal的子类。Animal类中定义了一个makeSound()方法,Cat和Dog类分别重写了这个方法。在main()方法中,我们创建了三个Animal类型的对象,并分别调用它们的makeSound()方法。由于animal2和animal3都是Animal类型的对象,但实际上它们分别是Cat和Dog类型的对象,因此在调用它们的makeSound()方法时,实际上是调用了它们各自的实现,也就是Cat类和Dog类中重写的makeSound()方法。这就是Java的表现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值