Java编译时类型与运行时类型

1. 定义

多态性是指相同类型的变量在调用同一个方法时,呈现出多种不同的行为特征。

2. 实例说明

在SubClass.java文件中存在两个类:一个是父类BaseClass,另一个是子类SubClass(继承自BaseClass类)。

class BaseClass{
    public int book = 6;
    public void base(){
        System.out.println("父类的普通方法");
    }
    public void test(){
        System.out.println("父类的被覆盖的方法");
    }
}

public class SubClass extends BaseClass {
    public String book = "轻量级Java EE企业应用实战";
    public void test(){
        System.out.println("子类的覆盖父类的方法");
    }
    public void sub(){
        System.out.println("子类的普通方法");
    }
    public static void main(String[] args) {
        // 将子类对象直接赋值给一个父类引用变量ploymophicBc
        BaseClass ploymophicBc = new SubClass();
        System.out.println(ploymophicBc.book);
        ploymophicBc.base();
        ploymophicBc.test();
//        ploymophicBc.sub();
    }
}
父类 BaseClass 子类 SubClass
book: int book: String
void base( ) void test()
void test() void sub( )
  • ⭐在子类的main( )方法中,BaseClass ploymophicBc = new SubClass();这行代码将一个子类对象直接赋给一个父类引用变量,无需任何类型转换(或称为向上转型,upcasting),这种向上转型由系统自动完成。
  • BaseClass ploymophicBc = new SubClass();这行代码中的这个引用变量ploymophicBc的编译时类型是BaseClass,而运行时类型是SubClass。当运行时调用该引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而非父类方法的行为特征。
ploymophicBc的编译时类型 ploymophicBc的运行时类型
BaseClass SubClass
  • System.out.println(ploymophicBc.book);这行代码访问的是父类对象的实例变量,即输出的是“6”。对象的实例变量不具备多态性,所以在程序中输出的是父类BaseClass类的实例变量的值6。
  • ⭐ploymophicBc.base();这行代码中引用变量ploymophicBc调用base( )方法将执行的是从父类继承得到的base( )方法,即输出的是“父类的普通方法”。
  • ⭐⭐⭐ploymophicBc.test();这行代码中当引用变量ploymophicBc调用test( )方法时(父类BaseClass中定义了该方法,而子类SubClass中则覆盖了父类的该方法),实际执行的是当前类的test( )方法,即子类SubClass类中覆盖后的test( )方法,即输出的是“子类的覆盖父类的方法”。
  • ⭐⭐⭐ploymophicBc.sub();这行代码会在编译时引发错误:Cannot resolve method 'sub' in 'BaseClass'。虽然引用变量ploymophicBc实际上确实包含了sub( )方法,但是因为它的编译时类型为BaseClass,因此在编译时无法调用sub( )方法。

3. 注意点

  • 引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法。
  • 个人理解:以ploymophicBc.test();这行代码为例,引用变量ploymophicBc在编译阶段只能调用其编译时类型(即父类BaseClass类)所具有的方法(即BaseClass类的test( )方法),但是在运行时它实际执行的是运行时类型(即子类SubClass类)所具有的方法(即SubClass类的test( )方法)。
  • 编写Java代码时,引用变量只能调用声明该变量时所用类里包含的方法。例如,通过Object p = new Person(); 这行代码定义了一个变量p,则这个变量p只能调用Object类的方法,而不能调用Person类里定义的方法。
  • 通过引用变量来访问其包含的实例变量时,系统总是试图访问它编译时类型所定义的成员变量,而不是它运行时类型所定义的成员变量。
  • ploymophicBc.base();、ploymophicBc.test();这两行代码能够运行、而ploymophicBc.sub();这行代码不能运行的根本原因就在于:
    • ①引用变量ploymophicBc在调用base( )方法的时候,由于它在编译时类型为BaseClass,并且BaseClass类中包含base( )方法,所以可以通过编译。在运行时由于SubClass类中不具有base( )方法,所以该引用变量在调用base( )方法的时候只能调用从父类BaseClass类继承而来的base( )方法。
    • ②引用变量ploymophicBc在调用test( )方法的时候,由于它在编译时类型为BaseClass,而BaseClass类中含有test( )方法,所以该行代码可以通过编译。个人理解就是借由编译时类型通过了编译,然后后头就根据“运行时则执行它运行时类型所具有的方法”这个原则,由于它运行时类型为SubClass,所以最终实际执行的时SubClass类所具有的test( )方法。
    • ③引用变量ploymophicBc在调用sub( )方法的时候,由于它在编译时类型为BaseClass,然而BaseClass类并没有sub( )方法,所以它连编译这一关都过不了,会报错。

 到此这篇关于Java编译时类型与运行时类型的文章就介绍到这了,更多相关Java编译时类型与运行时类型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

你可能感兴趣的:(Java编译时类型与运行时类型)