反射、类加载和new一个对象的过程的底层

  这段时间比较好奇类加载的一个过程,正好在知乎上看到了其中一个比较有意思的地方,就是创建一个对象的过程,描述的更加底层,这里做一个分享。
知乎链接:
https://www.zhihu.com/question/24304289

1.创建对象的过程,或者说new一个对象的过程如下:

在这里插入图片描述
  简单地描述就是,先把我们的.class文件进行类加载,然后把类文件信息存储在方法区中,并在堆内存中为我们的对象开辟一个空间。

2.对于反射的理解

  假如你写了一段代码:Object o=new Object();运行了起来!

  首先JVM会启动,你的代码会编译成一个.class文件,然后被类加载器加载进jvm的内存中,你的类Object加载到方法区中,创建了Object类的class对象到堆中,注意这个不是new出来的对象,而是类的类型对象,每个类只有一个class对象,作为方法区类的数据结构的接口。jvm创建对象前,会先检查类是否加载,寻找类对应的class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。

  上面的流程就是你自己写好的代码扔给jvm去跑,跑完就over了,jvm关闭,你的程序也停止了。

  为什么要讲这个呢?因为要理解反射必须知道它在什么场景下使用。

  可以想想上面的程序对象是自己new的,程序相当于写死了给jvm去跑。假如一个服务器上突然遇到某个请求哦要用到某个类,哎呀但没加载进jvm,是不是要停下来自己写段代码,new一下,哦启动一下服务器,(脑残)!

  反射是什么呢?当我们的程序在运行时,需要动态的加载一些类这些类可能之前用不到所以不用加载到jvm,而是在运行时根据需要才加载,这样的好处对于服务器来说不言而喻,举个例子我们的项目底层有时是用mysql,有时用oracle,需要动态地根据实际情况加载驱动类,这个时候反射就有用了,假设 com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection这两个类我们要用,这时候我们的程序就写得比较动态化,通过Class tc = Class.forName(“com.java.dbtest.TestConnection”);通过类的全类名让jvm在服务器中找到并加载这个类,而如果是oracle则传入的参数就变成另一个了。这时候就可以看到反射的好处了,这个动态性就体现出java的特性了!举多个例子,大家如果接触过spring,会发现当你配置各种各样的bean时,是以配置文件的形式配置的,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载,你的程序就能健壮地运行。

作者:chsfjz
链接:https://www.zhihu.com/question/24304289/answer/147529485
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

3.对于类加载的理解

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

类加载又分为几个步骤:
1)装载:查找并加载类的二进制数据;
2)链接:(细分为三个步骤)
验证:确保被加载类的正确性;
准备:为类的静态变量分配内存,并将其初始化为默认值;
解析:把类中的符号引用转换为直接引用;
3)初始化:为类的静态变量赋予正确的初始值;

那么上面说的符号引用和直接引用时什么呢?
符号引用时以一组符号来描述所引用的目标,引用目标并不一定加载到内存中;
直接引用可以指向目标的指针、相对偏移量或者是一个能够直接定位到目标的句柄,所引用的目标一定已经在内存中存在。

猜你喜欢

转载自blog.csdn.net/fallwind_of_july/article/details/101564420