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

目录
  • 1.定义
  • 2.实例说明
  • 3.注意点

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编译时类型与运行时类型内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java注解处理器学习之编译时处理的注解详析

    1. 一些基本概念 在开始之前,我们需要声明一件重要的事情是:我们不是在讨论在运行时通过反射机制运行处理的注解,而是在讨论在编译时处理的注解. 编译时注解跟运行时注解到底区别在什么地方?其实说大也不大,主要是考虑到性能上面的问题.运行时注解主要是完全依赖于反射,反射的效率比原生的慢,所以在内存比较少,CPU比较烂的机器上会有一些卡顿现象出现.而编译时注解完全不会有这个问题,因为它在我们编译过程(java->class)中,通过一些注解标示,去动态生成一些类或者文件,所以跟我们的APK运行完全没有

  • java学习之JVM运行时常量池理解

    运行时常量池 运行时常量池是方法区的一部分.Class文件中除了有类的版本.字段.方法.接口等描述信息外,还有一项信息时常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放. 运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用比较多的就是S

  • AndroidApk混淆编译时,报告java.io.IOException...错误解决办法

    在混淆编译之前,我的程序可以正常运行,混淆编译时,报告如下错误: Error:Execution failed for task ':gviews:transformClassesAndResourcesWithProguardForRelease'. Java.io.IOException: The same input jar [E:\Android\myProgram\angel\libs\alipaySdk-20160825.jar] is specified twice. 首先 看一下

  • java编译时与运行时概念与实例详解

    Java编译时与运行时很重要的概念,但是一直没有明晰,这次专门博客写明白概念. 基础概念 编译时 编译时顾名思义就是正在编译的时候.那啥叫编译呢?就是编译器帮你把源代码翻译成机器能识别的代码.(当然只是一般意义上这么说,实际上可能只是翻译成某个中间状态的语言.比如Java只有JVM识别的字节码,.另外还有啥链接器.汇编器.为了了便于理解我们可以统称为编译器) 那编译时就是简单的作一些翻译工作,比如检查老兄你有没有粗心写错啥关键字了啊.有啥词法分析,语法分析之类的过程.就像个老师检查学生的作文中有

  • java应用开发之JVM运行时内存分析

    目录 1.JVM的运行时内存也叫JVM堆 2.JVM新创建的对象 3.新生代详解 4.老年代详解 5.永久代 1.JVM的运行时内存也叫JVM堆 从GC的角度可以将JVM分为新生代,老年代,永久代.其中新生代默认占1/3的堆内存空间,老年代默认占2/3内存空间,永久代占非常少的堆内存空间方式. 而新生代分为Eden,SurvivorFrom,SurvivorTo区,Eden默认占8/10新生代区域空间,SurviorFrom和SurviorTo则占1/10. 2.JVM新创建的对象 JVM新创建

  • Java虚拟机运行时栈的栈帧

    目录 Java虚拟机栈概述 局部变量表 操作数栈 动态连接 方法的返回地址 结合javap命令理解栈帧 Java虚拟机栈概述 Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,它的生命周期与线程相同.虚拟机栈描述的是Java方法执行的内存模型:栈帧(Stack Frame)是用于支持Java虚拟机进行方法调用和执行的数据结构,它是虚拟机栈中的栈元素.每个方法在执行的同到都会创建一个栈帧用于存储局部变量表.操作数栈.动态链接.方法出口等信息. 在编译程序代码的

  • java编译时出现使用了未经检查或不安全的操作解决方法

    在本人用editplus写java文件时碰到的问题. 复制代码 代码如下: import java.util.*;class collection{    public static void main(String[] args) {        Collection c1=new ArrayList(25); c1.add(new String("one"));        c1.add(new String("two"));        String s

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

    目录 1.定义 2.实例说明 3.注意点 1. 定义 多态性是指相同类型的变量在调用同一个方法时,呈现出多种不同的行为特征. 2. 实例说明 在SubClass.java文件中存在两个类:一个是父类BaseClass,另一个是子类SubClass(继承自BaseClass类). class BaseClass{     public int book = 6;     public void base(){         System.out.println("父类的普通方法");

  • 详解Java虚拟机管理的内存运行时数据区域

    详解Java虚拟机管理的内存运行时数据区域 概述 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁. 程序计数器 程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器.在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等基

  • java异常继承何类,运行时异常与一般异常的区别(详解)

    一.基本概念 Throwable是所有异常的根,java.lang.Throwable Error是错误,java.lang.Error Exception是异常,java.lang.Exception Throwable: 有两个重要的子类:Exception(异常)和 Error(错误),二者都是 Java 异常处理的重要子类,各自都包含大量子类. Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题.大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java

  • Java内存模型与JVM运行时数据区的区别详解

    首先,这两者是完全不同的概念,绝对不能混为一谈. 1.什么是Java内存模型? Java内存模型是Java语言在多线程并发情况下对于共享变量读写(实际是共享变量对应的内存操作)的规范,主要是为了解决多线程可见性.原子性的问题,解决共享变量的多线程操作冲突问题. 多线程编程的普遍问题是: 所见非所得 无法肉眼检测程序的准确性 不同的运行平台表现不同 错误很难复现 故JVM规范规定了Java虚拟机对多线程内存操作的一些规则,主要集中体现在volatile和synchronized这两个关键字. vo

  • hadoop运行java程序(jar包)并运行时动态指定参数

    1)首先启动hadoop2个进程,进入hadoop/sbin目录下,依次启动如下命令 [root@node02 sbin]# pwd /usr/server/hadoop/hadoop-2.7.0/sbin sh start-dfs.sh sh start-yarn.sh jps 2)通过jps查看是否正确启动,确保启动如下6个程序 [root@node02 sbin]# jps 10096 DataNode 6952 NodeManager 9962 NameNode 10269 Second

  • c++ 完备的运行时类型信息(动态类型信息)

    众所周知,码猿写代码,自然要求严谨周密,殊不知想象力也很重要.本座阅码几十年,很是感概很多码猿的脑洞被大大禁锢,鲜有人能越雷池一步,特别是c++的同学,连同委员会的那一坨老头子,都很让人无语至极,出自这些人的作品,都是一个死鱼眼睛样子,千人一面,毫无灵动之生趣可言.stl,boost这些库都是这样子(虽然它们确实可以完成大多数日常任务),更别说其他的库,没有什么让人耳目一新之处. 就说说动态类型信息这块,又或者说是反射.自然,语言本身提供的废物type_info就懒得说了,除了证明c++也东施效

  • C++运行时类型识别与转换实现方法

    目录 1.运行时类型转换 2.typeid操作符 2.1类型转换到中间层次类型 2.2void型指针 2.3运用带模板的RTTI 3.多重继承 4.合理使用RTTI 5.RTTI的机制和开销 6.小结 当仅有一个指针或引用指向基类型时,利用运行时类型识别(RTTI)可以找到一个对象的动态类型. 运行时类型识别可能被认为是C++中一个”次要“的特征,当程序员在编程过程中陷入非常困难的境地时,实用主义将会帮助他走出困境.正常情况下,程序员需要有意忽略对象的准确类型,而利用虚函数机制实现那个类型正确操

  • java虚拟机运行时数据区分析

    JVMmemorymodel 这篇文章主要介绍在JVM规范中描述的运行时数据区(RuntimeDataAreas).这些区域设计用来存储被JVM自身或者在JVM上运行的程序所是用的数据. 我们先总览JVM,然后介绍下字节码,最后介绍不同的数据区域. 总览 JVM作为操作系统的抽象,保证同样的代码在不同的硬件或操作系统上的行为一致. 比如: 对于基本类型int,无论在16位/32位/64位操作系统上,都是一个32位有符号整数.范围从-2^31到2^31-1 无论操作系统或者硬件是大字节序还是小字节

随机推荐