Java 底层

jvm,类加载,反射

Java语言是跨平台语言,一段java代码,经过编译成class文件后,能够在不同系统的服务器上运行;因为java语言中有虚拟机jvm,才有了跨平台,java为了实现跨平台,在jvm上投入了很大的研发开发资源。jvm是java的底层,本文学习探讨下java的jvm及关联的类加载和反射知识

JVM

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

Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。 [1]

jvm的构成

jvm周期:是在java程序执行时运行,程序结束时停止

jvm的基本结构有:类加载子系统、本地方法栈、Java栈、方法区、Java堆、pc寄存器,垃圾回收,执行引擎

类加载子系统

java是面向对象语言,逻辑代码中的类文件执行逻辑前,是需要jvm读取class文件并校验初始化后才能使用的,包括变量,方法,构造。

类加载系统可以认为是在使用到java对像时(抽象),对java对象字节码的读取加载预编译(具体),之后不再加载(读取校验一次)。

Java栈

栈是先进后出的结构,java栈时一块线程私有的内存空间,可以理解为一个java线程对应一个java栈,栈和线程密切关联,栈包含线程运行的实时信息,如当前运行方法地址,方法中的瞬时变量等信息

方法区

在一个jvm实例的内部,类型信息被存储在一个称为方法区的内存逻辑区中。类型信息是由类加载器在类加载时从类文件中提取出来的。类(静态)变量也存储在方法区中。

Java堆

java堆是和应用程序关系最为密切的内存空间,几乎所有的对象都存放在堆上。并且java堆是完全自动化管理的,通过垃圾回收机制,垃圾对象会被自动清理,而不需要显示的释放。

pc寄存器

存放计算机下一步要执行的指令的地址,

垃圾回收

因为程序运行没创建一个对象都需要使用硬件的内存资源,不能无限使用,jvm的垃圾回收能够自动回收不再使用的java对象,使内存空间有效利用。垃圾回收线程是后台执行的,不需要认为回收内存垃圾,即使有垃圾回收方法调用,但并不能控制jvm如何去将一个对象失效回收。

执行引擎

Java 字节码指令指向特定逻辑得本地机器码,而JVM 解释执行Java字节码指令时,会直接调用字节码指向得本地机器码;

java底层由C语言编写,执行java程序时,jvm每读取一个字节码指令动作,执行引擎就解析解释执行本地系统对应的本地机器码。

类加载

虚拟机把描述类的数据从 Class 文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型,这就是虚拟机的类加载机制。

在Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的

双亲委派机制

作为软件开发语言,java在安全方面也有很高的要求,所以类加载是有一套规则的,jre是java运行时的环境,包括很多基本类,如java.lang.String 是字符串类,这个类很基础也很重要,那在加载的时候不能允许加载的String类被篡改,java保证类加载安全,首先看是否已经加载,如果没有查看核心库是否有此类,没有此类才会去扩展环境找类文件加载,这种机制保证了类在加载时的唯一性和安全性。

java类加载一般来说是询问自己的parentClassLoader 加载,如果没有加载成功,才自己加载,加载顺序是自上而下

java.lang.ClassLoader 加载类方法

  1. protected Class<?> loadClass(String name, boolean resolve)
  2. throws ClassNotFoundException
  3. {
  4. synchronized (getClassLoadingLock(name)) {
  5. // First, check if the class has already been loaded
  6. Class<?> c = findLoadedClass(name); //0.是否已加载
  7. if (c == null) {
  8. long t0 = System.nanoTime();
  9. try {
  10. if (parent != null) {
  11. c = parent.loadClass(name, false); //1.没有加载,首先通过父类加载器加载
  12. } else {
  13. c = findBootstrapClassOrNull(name); //1.没有父类加载器时加载方式
  14. }
  15. } catch (ClassNotFoundException e) {
  16. // ClassNotFoundException thrown if class not found
  17. // from the non-null parent class loader
  18. }
  19. if (c == null) {
  20. // If still not found, then invoke findClass in order
  21. // to find the class.
  22. long t1 = System.nanoTime();
  23. c = findClass(name);
  24. //如果父类没有加载到类,则使用findClass方法去加载类(这个方法可以重写自定义)
  25. // this is the defining class loader; record the stats
  26. sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
  27. sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
  28. sun.misc.PerfCounter.getFindClasses().increment();
  29. }
  30. }
  31. if (resolve) {
  32. resolveClass(c);
  33. }
  34. return c;
  35. }
  36. }

反射

反射是Java重要的技术点,在框架开发,AOP切面编程代理等方面都需要反射方面的技术去实现。

Java反射机制主要提供了以下功能:

  • 在运行时判断任意一个对象所属的类。
  • 在运行时构造任意一个类的对象。
  • 在运行时判断任意一个类所具有的成员变量和方法。
  • 在运行时调用任意一个对象的方法。
  • 生成动态代理。

反射相关的类

Class 类的字节码对象

Field 类的属性

Method 类的方法

Constructor 类的构造方法

Annotation 类(方法字段)的注解

反射的使用

一般使用

普通封装对象

  1. public interface People {
  2. String getName();
  3. void setName(String name);
  4. Integer getAge();
  5. void setAge(Integer age);
  6. BigDecimal getMoney();
  7. void setMoney(BigDecimal money);
  8. @defTransaction
  9. void addMoney(BigDecimal addNum);
  10. @defTransaction
  11. void subTractMoney(BigDecimal subNum);
  12. }
  1. public class TestPeople implements People{
  2. // 姓名
  3. public String name;
  4. // 年龄
  5. private Integer age;
  6. // 钱
  7. private BigDecimal money;
  8. public String getName() {
  9. return name;
  10. }
  11. public void setName(String name) {
  12. this.name = name;
  13. }
  14. public Integer getAge() {
  15. return age;
  16. }
  17. public void setAge(Integer age) {
  18. this.age = age;
  19. }
  20. public BigDecimal getMoney() {
  21. return money;
  22. }
  23. public void setMoney(BigDecimal money) {
  24. this.money = money;
  25. }
  26. @Override
  27. public void addMoney(BigDecimal addNum) {
  28. this.money = this.money.add(addNum);
  29. }
  30. @Override
  31. public void subTractMoney(BigDecimal subNum) {
  32. this.money = this.money.subtract(subNum);
  33. }
  34. }

反射测试类

  1. public class ReflectTest {
  2. public static void main(String[] args) {
  3. // 普通对象创建 使用new
  4. People testPeople = new TestPeople();
  5. testPeople.setName("Frank");
  6. testPeople.setAge(18);
  7. testPeople.setMoney(new BigDecimal(10));
  8. System.out.println("json:" + JsonUtil.objectToJson(testPeople));
  9. // 反射创建对象 class.newInstance()
  10. ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
  11. try {
  12. Class<?> clazz = contextClassLoader.loadClass("com.domoment.leaves.common.util.reflect.TestPeople");
  13. if(clazz != null) {
  14. Object people = clazz.newInstance();
  15. System.out.println("newInstance start json:" + JsonUtil.objectToJson(people));
  16. // 通过反射执行方法
  17. Method setName = clazz.getMethod("setName", String.class);
  18. setName.invoke(people, "inoverFrank");
  19. System.out.println("newInstance end json:" + JsonUtil.objectToJson(people));
  20. }
  21. } catch (Exception e) {
  22. e.printStackTrace();
  23. }
  24. }
  25. }

使用反射实现代理

代理类DefProxy (People是被代理类)


  1. public class DefProxy implements InvocationHandler{
  2. // 这个就是我们要代理的真实对象
  3. private Object subject;
  4. // 构造方法,给我们要代理的真实对象赋初值
  5. public DefProxy(Object subject){
  6. this.subject = subject;
  7. }
  8. @Override
  9. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  10. Annotation[] annotations = method.getDeclaredAnnotations();
  11. boolean transactionOpen = false;
  12. for (Annotation annotation : annotations) {
  13. if(annotation instanceof defTransaction) {
  14. transactionOpen = true;
  15. break;
  16. }
  17. }
  18. if(transactionOpen) { //当方法上有 defTransaction 注解时,执行方法前开启事务
  19. System.out.println("open Transaction");
  20. }
  21. System.out.println("proxy:" + method.getName());
  22. Object result = method.invoke(subject, args);
  23. if(transactionOpen) { //当方法上有 defTransaction 注解时,执行方法后关闭事务
  24. System.out.println("close Transaction");
  25. }
  26. return result;
  27. }
  28. }

模拟事务的注解

  1. @Target({ElementType.TYPE,ElementType.METHOD})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Inherited
  5. public @interface defTransaction {
  6. }
  1. public class ReflectTest {
  2. public static void main(String[] args) {
  3. // 反射创建对象
  4. ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
  5. try {
  6. Class<?> clazz = contextClassLoader.loadClass("com.domoment.leaves.common.util.reflect.TestPeople");
  7. if(clazz != null) {
  8. Object people = clazz.newInstance();
  9. System.out.println("newInstance start json:" + JsonUtil.objectToJson(people));
  10. Method setName = clazz.getMethod("setName", String.class);
  11. setName.invoke(people, "inoverFrank");
  12. System.out.println("newInstance end json:" + JsonUtil.objectToJson(people));
  13. InvocationHandler handler = new DefProxy(people);
  14. // 构造代理对象
  15. People proxyPeople = (People)Proxy.
  16. newProxyInstance(handler.getClass().getClassLoader(), people.getClass().getInterfaces(), handler);
  17. proxyPeople.setName("proxySetFrank");
  18. proxyPeople.setAge(20);
  19. proxyPeople.setMoney(new BigDecimal(999));
  20. System.out.println("proxyPeople end json:" + JsonUtil.objectToJson(people));
  21. proxyPeople.addMoney(new BigDecimal(20));
  22. System.out.println("proxyPeople add json:" + JsonUtil.objectToJson(people));
  23. proxyPeople.subTractMoney(new BigDecimal(17));
  24. System.out.println("proxyPeople end json:" + JsonUtil.objectToJson(people));
  25. }
  26. } catch (Exception e) {
  27. e.printStackTrace();
  28. }
  29. }
  30. }

Java jvm 类加载 反射的更多相关文章

  1. Java JVM类加载机制

    虚拟机的类加载机制是:JVM把描述类的数据从.class文件加载到内存,并对数据进行校验.解析.初始化,最终形成可以被JVM直接使用的Java类型. 加载.连接(验证.准备.解析).初始化.使用.卸载 ...

  2. Java虚拟机(四):JVM类加载机制

    1.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构 ...

  3. java基础——类加载与反射

    第1章 类加载器 1.1 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化. (1)加载 就是指将class文件读入内存,并为之创 ...

  4. JAVA程序类加载及其反射机制

    [IT168 技术]当调用java命令运行某个Java程序时,该命令将启动一条Java虚拟机进程,同一个JVM的所有线程,所有变量都处于同一进程里,它们都是用该JVM进程的内存区. 程序运行到最后正常 ...

  5. JVM(三)-java虚拟机类加载机制

    概述: 上一篇文章,介绍了java虚拟机的运行时区域,Java虚拟机根据不同的分工,把内存划分为各个不同的区域.在java程序中,最小的运行单元一般都是创建一个对象,然后调用对象的某个 方法.通过上一 ...

  6. Java JVM——2.类加载器子系统

    概述 类加载器子系统在Java JVM中的位置 类加载器子系统的具体实现 类加载器子系统的作用 ① 负责从文件系统或者网络中加载.class文件,Class 文件在文件开头有特定的文件标识. ② Cl ...

  7. Java基础篇(JVM)——类加载机制

    这是Java基础篇(JVM)的第二篇文章,紧接着上一篇字节码详解,这篇我们来详解Java的类加载机制,也就是如何把字节码代表的类信息加载进入内存中. 我们知道,不管是根据类新建对象,还是直接使用类变量 ...

  8. 【深入Java虚拟机】一 JVM类加载过程

    首先Throws(抛出)几个自己学习过程中一直疑惑的问题: 1.什么是类加载?什么时候进行类加载? 2.什么是类初始化?什么时候进行类初始化? 3.什么时候会为变量分配内存? 4.什么时候会为变量赋默 ...

  9. Java虚拟机(五):JVM 类加载机制

    一.JVM 类加载机制 JVM 类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程. 1. 加载: 加载是类加载过程中的第一个阶段,这个阶段会在内存中生成一个代表 ...

随机推荐

  1. 一、Git是什么?

    Git是什么? Git 是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控 ...

  2. Win10使用VMWare15安装Ubuntu-18.04.2-desktop-amd64

    本文在Win10系统中使用VMWare Workstation Pro 15.1.0虚拟机安装Ubuntu-18.04.2-desktop-amd64.iso系统,同时安装VMWare Tools(实 ...

  3. HotSpot VM执行引擎的实现

    Java代码的执行分类: 第一种是将源代码编译成字节码文件,然后再运行时通过解释器将字节码文件转为机器码执行 第二种是编译执行(直接编译成机器码).现代虚拟机为了提高执行效率,会使用即时编译技术(JI ...

  4. 并发编程(八)Lock锁

    一.引言 线程并发的过程中,肯定会设计到一个变量共享的概念,那么我们在多线程运行过程中,怎么保证每个先拿获取的变量信息都是最新且有序的呢?这一篇我们来专门学习一下Lock锁. 我们先来了解几个概念: ...

  5. spark源码分析, 任务提交及序列化

    简易基本流程图如下 1. org.apache.spark.scheduler.DAGScheduler#submitMissingTasks 2. => org.apache.spark.sc ...

  6. ser 序列化的使用

    2.序列化(serializers.Serializer) 1)序列化(正向查找) from rest_framework import serializers from users.models i ...

  7. 概率派VS贝叶斯派

    机器学习中的MLE和MAP两大学派的争论: 频率学派 - Frequentist - Maximum Likelihood Estimation (MLE,最大似然估计): 频率学派认为世界是确定的, ...

  8. python数据结构之二叉树的建立实例

    先建立二叉树节点,有一个data数据域,left,right 两个指针域 # coding:utf-8 class TreeNode(object): def __init__(self,left=N ...

  9. matlab中exist 检查变量、脚本、函数、文件夹或类的存在情况

    参考: 1.https://ww2.mathworks.cn/help/matlab/ref/exist.html?searchHighlight=exist&s_tid=doc_srchti ...

  10. matlab find函数使用语法

    find 找到非零元素的索引和值 语法: 1. ind = find(X) 2. ind = find(X, k) 3. ind = find(X, k, 'first') 4. ind = find ...