Java- 多态和虚方法调用

本文介绍了Java中的多态概念,包括编译时多态(重载)和运行时多态(覆盖和动态绑定)。详细讨论了虚方法调用,强调了其在实现运行时多态性中的作用。同时,文章还提到了上溯造型(upcasting)以及非虚方法的三种情况:static、private和final方法。

多态(polymorphism)

多态的概念

  • 多态是指一个程序中相同的名字表示不同的含义的情况。
  • 多态有两种情形:
    1. 编译时多态:
      • 重载(overload)多个同名的不同方法
      • 如:p.sayHello(); p.sayHello("wang");
    2. 运行时多态:
      • 覆盖(override)子类对父类方法进行覆盖
      • 动态绑定(dynamic binding)—-也成为虚方法调用(virtual method invoking),真正的方法在运行时才确定。
      • 在调用方法时,程序会正确地调用子类对象的方法。
  • 多态的特点大大提高了程序的抽象程度和简洁性。

上溯造型(upcasting)

  • 是把派生类型当作基本类型处理,如
        Person p = new Student();

        void  fun(Person p){...}
        fun(new Person());  or  fun(new Student());

虚方法 (virtual methods)

虚方法调用

  • 虚方法调用,可以实现运行时的多态
    • 子类重载了父类的方法时,运行时系统根据调用该方法的实例的类型来决定选择哪一个方法调用。
    • 所有的非final方法都会自动地进行动态绑定
public class TestVirtualInvoke{
    static void doStuff(Shape s){ // Shape为形式参数类型
        s.draw();
    }
    public static void main(String[] args) {
        Shape s = new Shape();
        Cricle c = new Cricle();
        Triangle t = new Triangle();
        Shape l = new Line(); // 可以将父类类型的引用指向子类的实例对象

        doStuff(s); 
        doStuff(c); // 调用的时候,使用其子类实例作为实参
        doStuff(t); // 运行时,系统根据调用方法的实例类型,来决定哪一个方法被调用
        doStuff(l);
    }
}

class Shape{
    void draw(){ System.out.println("Draw Shape"); }
}

class Cricle extends Shape{
    // 子类重载了父类的方法
    void draw(){ System.out.println("Draw Cricle"); }
}

class Triangle extends Shape{
    void draw(){ System.out.println("Draw Triangle"); }
}

class Line extends Shape{
    void draw(){ System.out.println("Draw Line"); }
}

-----------OUTPUT-----------  
Draw Shape
Draw Cricle
Draw Triangle
Draw Line

动态类型确定

  • 使用运算符instanceof
    • 作用:运行时用来指出对象是否是特定类的一个实例。通过返回一个布尔值,来指出对象是否是这个特定类或者是它的子类的一个实例
    • 用法:flag = Object instanceof Class
      • 如果Object是Class的一个实例,则返回true,否则,返回false。
public class InstanceOf{
    public static void main(String[] args) {
        Object things[] = new Object[3];
        things[0] = new Integer(1);
        things[1] = new Double(1);
        things[2] = new String("1");

        for (int i=0; i<things.length; ++i) {
            System.out.println("the type of things["+i+"] is " + things[i].getClass());
        }
    }
}

-----------OUTPUT-----------  
the type of things[0] is class java.lang.Integer
the type of things[1] is class java.lang.Double
the type of things[2] is class java.lang.String

什么情况不是虚方法的调用

  • Java中,普通方法是虚方法。即,不用做出特殊声明的方法都是虚方法。即,在被调用时是根据实际的对象实例选择调用哪个方法。
  • static,private方法不是虚方法调用。因为它们与虚方法编译后用的指令时不同的。(static是属于类的,不是具体某个类的;被private修饰的方法是不能被子类所override的)

三种非虚的方法

  • static的方法,以声明的类型为准,与实例类型无关。
  • private方法子类看不见,也不会被虚化
  • final方法子类不能覆盖,不存在虚幻问题
public class TestVirtualInvoke2{
    static void doStuff(Shape s){ 
        s.draw();   // 由于draw是static方法,所以只跟声明的类型有关,与实例无关
    }
    public static void main(String[] args) {
        Shape s = new Shape();
        Triangle t = new Triangle();
        Shape l = new Line(); 

        doStuff(s); 
        doStuff(t); 
        doStuff(l);

        System.out.println();

        Shape s2 = new Circle();
        // 只和声明的类型(Shape)有关,而跟后面的实例(Circle)无关
        doStuff(s2);
        s2.draw();

        Circle c = new Circle();
        c.draw();
    }
}

class Shape{
    // 把draw都改成static方法,与具体实例无关
    static void draw(){ System.out.println("Draw Shape"); }
}

class Circle extends Shape{
    static void draw(){ System.out.println("Draw Circle"); }
}

class Triangle extends Shape{
    static void draw(){ System.out.println("Draw Triangle"); }
}

class Line extends Shape{
    static void draw(){ System.out.println("Draw Line"); }
}

-----------OUTPUT-----------  
Draw Shape
Draw Shape
Draw Shape

Draw Shape
Draw Shape
Draw Circle
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值