介绍

什么是 java 的多态?

多态是面向对象编程的一个重要特性,父类中的属性方法被子类继承之后,可以具有不同的数据类型和表现出不同的行为,这可以让同一方法在其父类及其各个子类中具有不同含义

很简单,打个比方,有 Father 父类和 Son 子类,父类和子类中有一个同名的方法,该方法被子类重写,现在父类的引用指向子类的对象,那么父类的引用去使用这个同名的方法时候用的就是子类的方法实现而不是父类的方法实现了

多态离不开三个要素:继承重写子类往父类转型

下面我们通过内存,调用以及多态实现来观察
我们看几个有趣的例子:

父类和子类都是实体类
// 父类-实体类
public class Father {
	public int father = 0;
    public String param = "这是父类参数";
    public void fun(){
        System.out.println("这是父类方法");
    }
}

// 子类-实体类
public class Son extends Father {
	public int son = 0;
    public String param = "这是子类参数";
    public void fun(){
        System.out.println("这是子类方法");
    }
}

// 测试
public class Test {
    @org.junit.Test
    public void test(){
        Father f = new Son();
        System.out.println(f.param);
        f.fun();
        System.out.println("测试结束");
    }
}
  • 多态实现

    下面我查看一下测试结果:
    可以观察到,同名参数没有重新赋值,但是同名方法被重写了,并且向上转型的时候成功调用了子类的方法
    java多态的多种表现形式_实体类

  • 内存观察

    我们看一下父类的引用存储的数据:
    看来父类和子类的数据都能找的到,但实际上父类引用却无法调用子类数据,可以往下看
    java多态的多种表现形式_java_02

  • 调用数据

    可以看到调用的都是父类的数据
    java多态的多种表现形式_实体类_03

父类是抽象类,子类是实体类
// 父类-抽象类
public abstract class Father {
    public int father = 0;
    public String param = "这是父类参数";
    public abstract void fun();
}

// 子类-实体类
public class Son extends Father {
    public int son = 0;
    public String param = "这是子类参数";
    public void fun(){
        System.out.println("这是子类方法");
    }
}

// 测试
public class Test {
    @org.junit.Test
    public void test(){
        Father f = new Son();
        System.out.println(f.param);
        f.fun();
        System.out.println("测试结束");
    }
}
  • 多态实现

    父类是抽象类,就是说父类中所有的抽象方法,子类必须要重写
    我们看下结果:

    java多态的多种表现形式_# JVM语言_04

  • 内存观察

    父类的引用包含的数据如下:
    java多态的多种表现形式_多态_05

  • 调用数据

    父类的引用同样只能调用自己的数据:
    java多态的多种表现形式_多态_06

父类是接口,子类是实体类
// 父类-接口
public interface Father {
    public static final int father = 0;
    public static final String param = "这是父类参数";
    void fun();
}

// 子类-实体类
public class Son implements Father {
    public int son = 0;
    public String param = "这是子类参数";
    public void fun(){
        System.out.println("这是子类方法");
    }
}

// 测试
public class Test {
    @org.junit.Test
    public void test(){
        Father f = new Son();
        System.out.println(f.param);
        f.fun();
        System.out.println("测试结束");
    }
}
  • 多态实现

    父类中方法,子类必须都要重写
    我们来看控制台输出:

    java多态的多种表现形式_实体类_07

  • 内存观察

    我们看下内存数据:
    发现 f 中没有几个自己的变量了?这是怎么回事?原来这些接口中的变量根本就是属于 f,也不是变量,而是常量,所以下图中没有显示,即使接口中不去写 public static final,接口中也会把这些变量自动添加上 public static final
    java多态的多种表现形式_java_08

  • 调用数据

    下图也可以看见 f 中并无父类 param,因为他已经是 static 了,不属于父类成员变量的作用域了
    java多态的多种表现形式_多态_09