类的加载机制

类的加载机制

在这里插入图片描述

在这里插入图片描述
1.Java开发工具可以自动帮我们将java代码编译为class字节码。
2.类加载器加载class字节码,将字节码里面的指令放到内存执行,并将数据动态分配到jvm内存模型中。
3.jvm分区

类的加载流程

1.类的加载指的就是将class文件中的二进制数据读取到内存中。类,方法,常量,静态内容都放在方法区。
2.但是要在堆上面创建一个class对象,用来封装存储在方法区上面的数据结构。
3.类加载最终的结果就是在堆产生了一个Class对象(平时创建对象需要用到的内容)、当前对象提供了访问方法区内容的接口。

白话:创建一个类的时候,在堆内会自动创建一个java.lang,class对象 而不是类的实体对象,然后在你new一个新的对象的时候会找到这个Class对象然后去加载。任何一个类 new的时候一定会用Class对象去加载。这个Class对象就是类加载器。它并不需要等你去new的时候才产生,java虚拟机预料到你某个类要用这个对象加载的时候,会预先产生这个类加载器。

在这里插入图片描述
类加载器加载class文件,加载class文件有哪些方式?
1.从本地的系统读取的,读取过后直接加载
2.通过网络路径去下载的(class文件来自网络,可能会有错。本地的class文件一般是安全的,因为是经过本地的编译器编译过的)
3.从Zip、jar包中读取文档中的class文件
4.从某些数据库中去获取class文件
5.将java源文件动态编译成class文件。

类的生命周期:
在这里插入图片描述

加载:查找并加载类的二进制的数据
1.通过类的全限定名来获取定义的二进制数据
2,。将这个字节流的所代表的静态存储内容放入方法区
3.Java堆中生成一个代表当前对象的java.lang.Class对象,作为方法区的访问接口。整个类的生命周期中,最容易控制的阶段就是当前加载阶段。程序员最好控制这块、你可以自己定义类加载器来加载数据。

验证:验证的目的主要是确保被加载的类的正确性
验证主要的内容是验证class文件中的信息是符合java虚拟机加载的要求。并且你的信息不能够危害java虚拟机的安全。

验证的内容:
1.文件格式的验证:常量池中的数据是否有不被支持的类型
2.元数据的验证:保证类所描述的信息是符合java规范的。当前这个类是否有父类,除了java.lang.Object之外
3.字节码校验:校验语法的正确性,是否符合逻辑
4.符号引用校验:确保解析的动作能够正确运行

校验阶段是非常重要的阶段,但是又不是必须的。

准备:为类的静态变量分配内存,并且进行初始化为默认值。
为类变量(所有static静态的东西都称为类变量,属于类的属性。private等声明的是对象的属性)分配内存、并且默认初始化

1.进行内存分配的时候仅包含static变量,不包括实例变量。实例变量对象创建的时候才分配内存。Static变量在方法区 实例变量–堆
2.这是所设置的初始值包括数据类型默认的值 int(0),String(null),Object(null),这个阶段数据默认值,髌骨会使用你自己定义的值 如public static int numbe=10

解析:将类中符号转化为直接引用
虚拟机将常量池中的符号引用转化为直接引用。解析的动作主要包括:类、接口、字段、接口方法、方法类型。

直接引用:直接指向目标对象的指针。寻址操作。

解析阶段顺序并不一定按照图中的顺序执行,有可能在初始化过后才会执行这个动作。

初始化:给类的静态变量进行赋值,jvm负责对类进行初始化,主要是对类的变量进行初始化
1.声明类变量的时候指定初始化值。
2.使用静态快来初始化值。

jvm 判断:
假如当前类的父类还没有初始化,先初始化父类。
假如类中有初始化语句,依次执行初始化操作。

成员变量初始化:new的时候,反射的时候、初始化子类的时候,父类也会初始化。

类的销毁&对象的销毁
类的销毁:java虚拟机中的内容和 java.lang.class的销毁。
比如:system.exit(0) 退出虚拟机
程序正常运行结束。Java,lang,class。
程序遇到异常终止的情况。

如果深入了解本块内容 详情参考《深入理解java虚拟机》

《think in java》

类加载器

一共分为三类(系统架构提供的、不包括自己写的):
1.启动类加载器(Bootstrap ClassLoder)(用于加载系统的):主要负责加载存放在JDK/jre/lib文件夹下面的内容。并且能被jvm识别为类库。当前启动类加载器是无法直接被java程序引用的。
2.扩展类加载器:(Extension ClassLoder)(用于加载系统的):主要负责加载JDK/jre/lib/ext 目录下的内容。比如(javax.*包)
3.应用程序类加载器(Application ClassLoader)(用于加载自己的):负责加载用户类路径下面的类(自己写的类),操作系统配置的环境变量,自己在开发中写的java类。若没有自定义类加载器,默认一般都是用它来加载应用程序。

应用程序在运行的过程中,是由上面三种加载器相互配合执行的,并非由哪一个单独完成的。

在这里插入图片描述
注意:图中的方向并不是表示继承关系,而是组合关系。

加载机制

1.全盘负责:当一个类加载器负责加载某个类(Class)的时候,如果这个Class所依赖的其他class也由当前这个类加载器来完成。
2.父类委托:先让父加载器加载该内容,只有父加载器无法加载的时候再尝试自己加载
3.缓存机制:缓存机制主要是保证已经被加载过的类被缓存起来,当下次要再加载这个类的时候,直接从缓存区获取即可。一旦修改了Class,必须重启jvm才能生效。

在这里插入图片描述
在这里插入图片描述

类加载器既然可以加载本地类,创建一个本地类(里面只输出了一句话”正在执行静态块“)
加载类要用到类的全限定名称

返回的就是一个Class 并不是student,这时候堆里面并没有student 一个对象呗类加载器加载,会在堆里面产生一个class class就是你访问变量 访问方法区的一个访问入口。以后new 一个student 就是通过这个class来产生的,但是lcass只有一个。,
在这里插入图片描述

发现可以强转

newInstance就相当于创建对象,不用new。 这种创建方式称为动态加载(new 属于静态加载)
在这里插入图片描述

类加载:

1.Jvm启动的时候有Jvm来加载(自动加载)
2.ClassLoader.loadClass();(手动加载)
3.Class.forName();(手动加载)
在这里插入图片描述

1。TestMain.class.getClassLoader—类加载器

Load.loadClass();

2.Class.forname(”com.project.bean.StudentBean“);也可以加载类

双亲委派模型:

工作流程:
1.当ApplationClassloader加载一个class的时候,首先自己不会尝试加载这个类,而是将类加载委托给父类,父类交给extClassLoader,
2.当EXTClassload加载一个Class的时候,它首先不会尝试自己去加载,而是将当前类交给
BootStrapClassload,
3.此刻交给BootStrapClassloader加载,但是如果加载失败,?Jre/lib获取不到类信息,又会委托EXTBoostrap来加载
4.EXT加载失败,这个时候才会交给ApplicationClassloader加载。如果ApplicationClassloader还加载失败了,抛异常。显示ClassNotFoundException

双亲委派模型的意义:
防止内存中出现多分同样的字节码,保证java程序运行稳定,一个Class只加载一次。

先委托俩父元素加载,不行了再回来,保证整个系统内存中只有一个字节码、。

反射

1.类加载 Class.forname(“类的名称”) ClassLoader.loadclass(“类名”)

类表现了面向对象的封装特征。万物皆对象。

问:静态成员变量,普通的数据类型是否是对象?

int m =10;

普通的数据类型不是对象,但是java提供了包装类来表示基本数据类型,就是一种对象。

Integer number =10; Interger number = new Integer();

静态成员变量可以看成类的属性。


类:是?的对象
类是对象,类是java.lang,Class的对象。类的数据类型还是类
在这里插入图片描述
这里的类指的是我们创建出来的类


2.什么是动态加载、什么是静态加载?

在java中,类的加载 或者对象的加载分为两种,一种是静态加载,一种是动态加载。

静态加载:在你类编译的时候,就已经在内存中加载了。比如new一个对象

动态加载:在类运行的时候才会去主动加载。比如反序列化、反射产生对象。

优缺点:
静态加载,在编译的时候就加载,以后要用的时候不需要再编译了。但是消耗内存。
动态加载,在编译的时候不会加载对象,而是需要用某个功能的时候再加载。不会浪费内存资源,效率更低。

在项目开发中,两种方式都会用,一般来说框架的底层大量要用动态加载。

3.Class类的获取方式
Java.lang Class存放在堆中,在程序中要获取当前对象提供了三种方式:

Object—getClass() 所有对象都有当前方法
对象.class 静态属性 class静态属性任何一个对象都有。
Class C= Class forName(“类的全路径”);

总结:在运行期间,一个类只会产生一个Class 对象,第一个方式获取类的对象意义不大,必须得由对象才能反向获取。第二种方式需要导入当前对象(导入javabean包),依赖性太强。第三种方式只需要知道类的名称(String)就可以获取类的类型。

反射的操作:
1.通过反射可以获取到构造方法并使用
通过Class对象获取到某个类中:构造方法、成员变量、成员方法


UserBean:两个公共的有参无参构造器,一个私有的有参构造器(图中未显示)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

访问对象私有的构造器:调用
在这里插入图片描述

在这里插入图片描述
发现可以获取到了
在这里插入图片描述
获取到了,能不能用?正式传实参进去
在这里插入图片描述
提示是无法访问的,构造器是私有的。接下来使用暴力破解:

在这里插入图片描述
发现就可以获取了。


获取到所有的公有属性
在这里插入图片描述
在这里插入图片描述


获取到某一个公有属性
在这里插入图片描述
在这里插入图片描述


获取到一个私有的属性
在这里插入图片描述
在这里插入图片描述


给私有属性设值 set方法

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值