在了解JVM之前,我们要思考一个小问题,
面试过程中,我们会遇到面试官 广度
不难发现,我们谈对java的理解可以参照面向对象思想面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式,java的每一个特性都可以看成是java中的一个对象,不同的对象中有不同的方法和数据,而对于平台无关性这一特性,JVM则可以看作是其中的主方法
JVM的广度定义:JVM是JavaVirtualMachine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。 主流虚拟机
如果把java看成是一个工厂,java的平台无关性则是一个小的车间,那么JVM即可看成一个机器,那么这个问题就再问这个车间是如何运转的;
java源码首先编译为源码,之后由不同的平台的JVM进行解析,java在不同的平台上运行时不需要进行重新编译,java虚拟机在执行字节码时,把字节码转化为不同平台上的指令
这段话我们可以理解为在一个专用车间将原料转化为机器所需的通用原料,然后将通用原料交给其它不同车间的机器(JVM)处理,即不需要再 在制作工具的车间重新进行原料的转换;
拓展:javac可对程序进行编译,其先对于程序的语法进行检测,编译完后生成class文件,class文件保存的是java文件翻译成的二进制字节码,如下图:
Java的字节码示例如图所示:
为什么JVM不直接将源码解析为机器码执行,而是先编译为class文件之后在执行:
对于这个问题我们也可以这样理解,java程序的运行是一个造纸的过程,我们可以将执行java命令得到的结果看成是最终得到的不同的纸,如果将java文件看作是木头等生产原料,那么class文件就相当于木浆,我们要先在一个专用车间(即为javac进行编译)将各种原料转化为造纸用的木浆,只有转换后我们才能直接将木浆送到各个专用车间加个得到不同的纸张(专用车间即为不同平台上的JVM),
如果我们省去这一步,而是直接将木头等原料送到各种车间进行加工,我们就要在各种车间添加将原料变为木浆的工具,这一过程会造成效率的下降,使得在造纸的过程还要多一步原料转化的过程,
这一过程很好的体现的java面向对象的思想,将不同的方法交由专用的对象处理,就像生活中我们要尽量把不必要的事情交给专业的人处理,不但能很好的效率,我们还能得到更优质的体验;同时这一过程作为JVM供应链的一环,为java的兼容性提供保证,不难知道,兼容性是一个app,一款硬件,乃至一个操作系统能够推广并发挥最大作用的保证,这个过程很好的保证的java文件只编译一次,但可以在不同的平台执行无数次,符合软件的中庸之道
在了解完java的平台无关性,JVM的运行流程等,我们还需要了解JVM运行具体的过程
我们先看一下java虚拟机的定义:
虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的硬体架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
对于这两个优点,我们可以不太容易了解到其中的内涵,下面我们先了解JVM的一些运行原理:
要回答这个问题,我们要先了解JVM的内存结构,即为机器的整体的构造,其中大致可分为四个部分;
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键
即为机器如何监视,保证生产正常进行
反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。
其次,通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。
再次,使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。
最后,反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。
反射的具体机制我们以后在深究…
下面我们要了解一下机器的具体造纸过程
原料从制作到变为产品的过程;
可以看作是机器的引擎,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
这个以后会探讨…
引擎内部运行的过程有两个方式:自底向上和自上向下(可以看作为引擎在生产过程中的索所要遵循的规则)
类是先向上委派之后向下查找
可先参考一下loaderclass方法的源码;
使用双亲委派机制加载类的原因:
1.这样做的原因主要是为了安全,避免程序员编写类动态替换Java的核心类比如说String,
2.同时也是避免了相同的class类被不同的ClassLoader重复加载
可以理解为得到的纸张的方式;
类的装载过程:
加载的方式:
1.隐式加载:new
2.显示加载:loadclass,forname
具体区别: