• (一)JVM的简单了解--java平台无关性的实现


    (一)JVM初步介绍:

    在了解JVM之前,我们要思考一个小问题,

    1.谈谈你对java的理解:

    面试过程中,我们会遇到面试官 广度

    • 面向对象 (继承 封装和多态)
    • 平台无关性
    • GC (不同于C++,java可以自动回收内存)
    • 语言特性
    • 类库
    • 异常处理

    不难发现,我们谈对java的理解可以参照面向对象思想面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式,java的每一个特性都可以看成是java中的一个对象,不同的对象中有不同的方法和数据,而对于平台无关性这一特性,JVM则可以看作是其中的主方法

    JVM的广度定义:JVM是JavaVirtualMachine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 主流虚拟机

    2.平台无关性如何实现:

    如果把java看成是一个工厂,java的平台无关性则是一个小的车间,那么JVM即可看成一个机器,那么这个问题就再问这个车间是如何运转的;

    java源码首先编译为源码,之后由不同的平台的JVM进行解析,java在不同的平台上运行时不需要进行重新编译,java虚拟机在执行字节码时,把字节码转化为不同平台上的指令

    过程为 : java文件–>class文件–>转化成特定平台的执行指令(JVM解析)

    这段话我们可以理解为在一个专用车间将原料转化为机器所需的通用原料,然后将通用原料交给其它不同车间的机器(JVM)处理,即不需要再 在制作工具的车间重新进行原料的转换
    拓展:javac可对程序进行编译,其先对于程序的语法进行检测,编译完后生成class文件,class文件保存的是java文件翻译成的二进制字节码,如下图:
    javac的编译
    Java的字节码示例如图所示:
    在这里插入图片描述

    额外:

    为什么JVM不直接将源码解析为机器码执行,而是先编译为class文件之后在执行:

    • 准备工作:如果不编译为class文件,则每次执行都要进行各种检查,整体性能会受到影响
    • 兼容性:可以将别的语言解析为字节码,可以更好的体现软件的兼容性

    对于这个问题我们也可以这样理解,java程序的运行是一个造纸的过程,我们可以将执行java命令得到的结果看成是最终得到的不同的纸,如果将java文件看作是木头等生产原料,那么class文件就相当于木浆,我们要先在一个专用车间(即为javac进行编译)将各种原料转化为造纸用的木浆,只有转换后我们才能直接将木浆送到各个专用车间加个得到不同的纸张(专用车间即为不同平台上的JVM),
    如果我们省去这一步,而是直接将木头等原料送到各种车间进行加工,我们就要在各种车间添加将原料变为木浆的工具,这一过程会造成效率的下降,使得在造纸的过程还要多一步原料转化的过程,

    这一过程很好的体现的java面向对象的思想,将不同的方法交由专用的对象处理,就像生活中我们要尽量把不必要的事情交给专业的人处理,不但能很好的效率,我们还能得到更优质的体验;同时这一过程作为JVM供应链的一环,为java的兼容性提供保证,不难知道,兼容性是一个app,一款硬件,乃至一个操作系统能够推广并发挥最大作用的保证,这个过程很好的保证的java文件只编译一次,但可以在不同的平台执行无数次,符合软件的中庸之道

    (二)深入理解JVM:

    在了解完java的平台无关性,JVM的运行流程等,我们还需要了解JVM运行具体的过程

    我们先看一下java虚拟机的定义:
    虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。

    • 我们可以总结两个优点:
      1.屏蔽底层操作系统的不同
      2.减少基于原生语言开发的复杂性

    对于这两个优点,我们可以不太容易了解到其中的内涵,下面我们先了解JVM的一些运行原理:

    JVM如何加载.class文件:

    要回答这个问题,我们要先了解JVM的内存结构,即为机器的整体的构造,其中大致可分为四个部分;

    完整结构:在这里插入图片描述

    • class loader:根据特定形式,加载class文件到内存(这里看成是机器的原料进入口,把符合要求的原料放入机器当中)
    • Rxecution Engine:对命令进行解析(这一步可以看成是对原料进行加工,是造纸前的一个准备工作)
    • Native Interface:融合不同的开发语言的原生库为java所用(这一部分可以看成调取其它不同的原料(即为其它语言,例如C++,有些时候C++的效率反而更高,JVM的内核就是由C++编写)的过程,可以理解为,为了得到不同功能的纸张,我们要添加一些其它的原料提高质量)
    • runtime data Area: JVM的内存空间结构模型(我们所写的java文件最终都会被加载到这里,因此可以把此部分看成存储原料的引擎)
      为了在生产过程中保证生产能够有序的进行,我们还要在不同的是时间对于生产进行监督,即为反射:

    反射机制(RC):

    • java反射机制的定义如下:

    Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键
    即为机器如何监视,保证生产正常进行

    • 反射的优点:

    反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。
    其次,通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。
    再次,使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。
    最后,反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。
    反射的具体机制我们以后在深究…

    下面我们要了解一下机器的具体造纸过程

    类从编译到执行的过程:

    原料从制作到变为产品的过程;

    • 编译器将Robet.class文件编译为Robet.class字节码文件
    • classLoader将字节码转化为JVM中的class(Robet)对象
    • JVM利用Class(Robet )对象实例化为Robet对象

    classLoader(类加载器):

    可以看作是机器的引擎,Classloader 类加载器,用来加载Java类到 Java 虚拟机中的一种加载器。

    JVM本身包含了一个ClassLoader称为Bootstrap ClassLoader,和JVM一样,BootstrapClassLoader是用本地代码实现的,它负责加载核心JavaClass(即所有java.*开头的类)。另外JVM还会提供两个ClassLoader,它们都是用Java语言编写的,由BootstrapClassLoader加载;其中Extension ClassLoader负责加载扩展的Javaclass(例如所有javax.*开头的类和存放在JRE的ext目录下的类),ApplicationClassLoader负责加载应用程序自身的类。

    当运行一个程序的时候,JVM启动,运行bootstrapclassloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程。

    这一过程我们可以将classloader看作是机器的引擎,而三个
    classLoader的种类既可以看作是引擎的内部不同处理系统,由一个核心部分搭配另外两个部分完成所有功能;

    • 1.BootstrapClassLoader:C++编写,加载核心库;
      BootstrapClassLoader是顶级加载器,默认加载的是%JAVA_HOME%中lib下的jar包和class类文件,他也是ExtClassLoader的父类,但是不是继承(extends)关系,是ExtClassLoder中有一个parent变量是BootstrapClassLoader

    • 2.ExtClassLoader:java编写,加载拓展库javax
      ExtClassLoader扩展类加载器,负责加载%JAVA_HOME%中lib/ext文件下的jar包和class类文件,ExtClassLoader加载器是AppClassLoader的父类,当然也不是继承(extends)关系,也是类中有parent变量

    • 3.AppClassLoader:java编写,加载程序所在的目录
      AppClassLoader(应用程序加载器/系统类加载器)是自定义加载器的父类,负责加载classPath下的类文件,平时引用的jar包以及我们自己写的类都是这个加载器进行加载的,同时AppClassLoader还是线程上下文加载器,如果想实现一个自定义加载器的话就继承(extends)ClassLoader来实现.

    • 4.自定义classloader
      这个以后会探讨…

    (三)额外:

    1.classLoader双亲委派机制:

    引擎内部运行的过程有两个方式:自底向上和自上向下(可以看作为引擎在生产过程中的索所要遵循的规则)

    类是先向上委派之后向下查找
    在这里插入图片描述

    • 1.自底向上:AppClassLoader是加载我们自己编写的class类的,当他遇到一个新的class类的时候,不会直接进行加载,而是向上委派给ExtClassLoader,向上委派就是去查找ExtClassLoader是否缓存了这个class类,如果有则返回,如果没有则继续委派给BootstrapClassLoader,如果BootstrapClassLoader中缓存有则加载返回

    可先参考一下loaderclass方法的源码;

    在这里插入图片描述

    • 2.自上向下:开始进行向下查找了,就意味着当前class类向上委派到BootstrapClassLoader时还是没有该类的缓存,此时BootstrapClassLoader会查找加载自己路径也就是%JAVA_HOME%/lib下的jar与class类文件,如果有则加载返回,没有则继续向下查找。ExtClassLoader也是做同样的操作。查找加载ExtClassLoader对应路径的文件,如果有则加载返回,没有则继续向下到AppClassLoader查找加载,AppClassLoader是加载classPath也就是我们程序员自己编写的class类,如果AppClassLoader找不到则会抛出找不到class类异常

    使用双亲委派机制加载类的原因:
    1.这样做的原因主要是为了安全,避免程序员编写类动态替换Java的核心类比如说String,
    2.同时也是避免了相同的class类被不同的ClassLoader重复加载

    2.类的装载过程:

    可以理解为得到的纸张的方式;

    类的装载过程:

    • 加载:加载class文件字节码
    • 链接:校验,准备,解析;
    • 初始化
      在这里插入图片描述

    加载的方式:
    1.隐式加载:new
    2.显示加载:loadclass,forname

    具体区别:
    在这里插入图片描述

  • 相关阅读:
    安装Oracle、连接Oracle遇到的一系列问题
    Python如何解析json对象?
    设计模式① :适应设计模式
    建设网站制作公司的选择标准是什么?
    获取、设置注释的值
    沿面闪络放电测量装置中的真空度精密控制解决方案
    【周赛复盘】力扣第 85 场双周赛
    java计算机毕业设计简易在线教学系统源码+数据库+系统+lw文档+mybatis+运行部署
    Ubuntu20.04 Server 安装NS3 速通版
    榕树贷款GPU 硬件架构
  • 原文地址:https://blog.csdn.net/roothahh/article/details/125522283