Java高级特性——反射机制(第二篇)
在Java高级特性——反射机制(第一篇)中,写了很多反射的实例,可能对于Class的了解还是有点迷糊,那么我们试着从内存角度去分析一下。
Java内存

从上图可以看出,Java将内存分为堆、栈、方法区,其中方法区是一种特殊的堆。
堆:堆中通常存放new的对象和数组,可以被所有的线程共享,不会存放别的对象引用。
栈:存放基本的变量类型(会包含这个基本类型的具体数值)以及引用对象的变量(会存放这个引用在堆里边的具体地址)。
方法区:可以被所有的线程共享,包含了所有的class和static变量。‘
类的加载过程(了解即可)
当程序主动使用某个类时,如果该类还未被加载到内存,系统会通过如下三个步骤对该类进行初始化:

第一步(加载):将类的 .class 文件读入内存,并将这些静态数据转化为方法区运行时的数据结构,然后生成一个代表这个类的java.lang.Class对象。这个过程由类加载器完成。
第二步(链接):将Java类的二进代码合并到JVM的运行环境JRE中,分为下面三个步骤:
>验证:确保加载类的信息符合JVM规范,并没有安全方面的问题。
>准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
>解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
第三部(初始化):JVM负责对类进行初始化,过程如下:
>执行类构造器<clinit>()方法的过程,类构造器<clinit>()方法是由编译期自动收集类所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)
>当初始化一个类的时候,如果发现其父类还没有初始化,则需要先触发其父类先初始化。
· >虚拟机会保证一个类<clinit>()方法在多线程环境中正确加锁和同步。
举例测试:
package test;
import java.lang.annotation.ElementType;
public class Test{
public static void main(String[] args) {
A a = new A();
System.out.println(a.m);
/*
* 1.加载到内存,会产生一个类对应的class对象
* 2.链接:链接结束后,m=0
* 3.初始化
* <clinit>(){
* System.out.println("A类的静态代码块被加载");
m=300;
m=100;
* }
* 最后:m=100
*/
}
}
class A{
static {
System.out.println("A类的静态代码块被加载");
m=300;
}
static int m=100;
public A() {
System.out.println("A类的无参构造方法初始化");
}
}
运行结果:

类的初始化
什么时候会发生类的初始化?
1.类的主动引用(一定会发生类的初始化)
>当虚拟机启动时,先初始化main方法所在的类。
>new一个类的对象。
>调用类的静态成员(除了final常量)和静态方法。
>使用java.lang.reflect包的方法对类的反射进行调用。
>当初始化一个类,当父类没有被初始化,则会先初始化它的父类。
举例(2-1):
package test; //测试类什么时候会被初始化
public class Test{
static {
System.out.println("main类被加载");
} public static void main(String[] args) throws ClassNotFoundException { //主动引用
//Son son = new Son(); //反射也会产生主动引用
Class.forName("test.Son"); //两者输出结果均一样
/*
* 结果为:
* main类被加载
* 父类被加载
* 子类被加载
*/
} } class Father{ static int b = 1; static {
System.out.println("父类被加载");
}
} class Son extends Father{
static {
System.out.println("子类被加载");
m = 300;
} static int m = 100; static final int M = 1;
}
打印结果为:

2.类的被动引用(不会发生类的初始化)
>当访问一个静态域时,只有真正声明这个域的类才会被初始化。例如:当通过子类引用父类的静态变量,不会导致子类初始化。
>通过数组定义类引用,不会触发此类的初始化。
>引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)。
举例(改变例2-1的main方法):
public static void main(String[] args) throws ClassNotFoundException {
//不会产生引用的方法
//System.out.println(Son.b);
//Son[] sons = new Son[10];
System.out.println(Son.M);
}
执行结果一个一个去测试一下!
类加载器
>类加载器的作用:将class文件字节码内容加载到内存中,并将这些静态数据转化为方法区运行时数据结构,然后在堆中生成一个java.lang.Class对象,作为方法区中类数据的访问入口。
>类缓存:标准的Java SE类可以按要求查找类,但是一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制(gc)可以回收这些Class对象。

类加载器的作用
类加载器的作用:把类(class)装载进内存。
JVM规范定义了如下类型的类加载器:

>引导加载器(Bootstap ClassLoader):用C++编写的,是JVM自带的类加载器,负责Java平台的核心库,用来装载核心类库(rt.jar),该加载器无法直接获取。
>扩展类加载器(Extension ClassLoader):负责jre\lib\ext目录下的jar包或 -D java.ext.dirs指定目录的jar包装入工作室。
>系统加载器(System ClassLoader):负责java -classpath 或者-D java.class.path所指目录下的类与jar包装入工作,是最常用的加载器。
举例获取加载器:
package test;
public class Test{
public static void main(String[] args) throws ClassNotFoundException {
//获取类加载器
ClassLoader c1 = ClassLoader.getSystemClassLoader();
System.out.println(c1);
//获取类加载器的父类加载器-->拓展类加载器
ClassLoader c2 = c1.getParent();
System.out.println(c2);
//获取拓展类加载器的父类加载器-->根加载器(C/C++ Tip:获取不到返回NULL)
ClassLoader c3 = c2.getParent();
System.out.println(c3);
//测试当前加载器是由哪个类加载的
ClassLoader c4 = Class.forName("test.Test").getClassLoader();
System.out.println(c4);
//测试JDK是由哪个加载器加载的
ClassLoader c5 = Class.forName("java.lang.Object").getClassLoader();
System.out.println(c5);
//如何获取系统类加载器可以加载的路径
System.out.println(System.getProperty("java.class.path"));
//双亲委派机制 学习链接(https://blog.csdn.net/shy415502155/article/details/88167713)
/*
C:\Program Files\Java\jdk1.8.0_131\jre\lib\resources.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\jsse.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\jce.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\charsets.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\jfr.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\access-bridge-64.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\cldrdata.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\dnsns.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jaccess.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\jfxrt.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\localedata.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\nashorn.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunec.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunjce_provider.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunmscapi.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\sunpkcs11.jar;
C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\zipfs.jar;
G:\test\bin
*/
}
}
打印结果:

Java高级特性——反射机制(第二篇)的更多相关文章
- Java高级特性——反射机制(第一篇)
——何为动态语言,何为静态语言?(学习反射知识前,需要了解动态语言和静态语言) 动态语言 >是一类在运行时可以改变其结构的语言,例如新的函数.对象.甚至是代码可以被引进,已有的函数可以被删除或者 ...
- Java高级特性——反射机制(第三篇)
获取类运行时的结构 通过反射获取运行时类的完整结构 Field.Method.Constructor.Superclass.Interface.Annotation >实现的全部接口 >所 ...
- Java高级特性——反射机制(完结)——反射与注解
按照我们的学习进度,在前边我们讲过什么是注解以及注解如何定义,如果忘了,可以先回顾一下https://www.cnblogs.com/hgqin/p/13462051.html. 在学习反射和注解前, ...
- Java高级特性——反射
感谢原文作者:peter_RD_nj 原文链接:https://www.jianshu.com/p/9be58ee20dee 注意:同一个类在JVM中只存在一份字节码对象 概述 定义 JAVA反射机制 ...
- java的反射机制(第二篇)
本文转载自:http://c.biancheng.net/cpp/html/1781.html 要理解RTTI在Java中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工作是由“Class ...
- JAVA高级特性反射和注解
反射: 枚举反射泛型注解.html34.3 KB 反射, 主要是指通过类加载, 动态的访问, 检测和修改类本身状态或行为的一种能力, 并能根据自身行为的状态和结果, 调整或修改应用所描述行为的状态和相 ...
- Java高级特性—反射和动态代理
1).反射 通过反射的方式可以获取class对象中的属性.方法.构造函数等,一下是实例: 2).动态代理 使用场景: 在之前的代码调用阶段,我们用action调用service的方法实现业务即可. 由 ...
- Java高级特性 第5节 序列化和、反射机制
一.序列化 1.序列化概述 在实际开发中,经常需要将对象的信息保存到磁盘中便于检索,但通过前面输入输出流的方法逐一对对象的属性信息进行操作,很繁琐并容易出错,而序列化提供了轻松解决这个问题的快捷方法. ...
- 浅说Java中的反射机制(一)
在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...
随机推荐
- 牛客练习赛63 C 牛牛的揠苗助长 主席树 二分 中位数
LINK:牛牛的揠苗助长 题目很水 不过做法很多 想到一个近乎O(n)的做法 不过感觉假了 最后决定莽一个主席树 当然 平衡树也行. 容易想到 答案为ans天 那么一些点的有效增长项数为 ans%n. ...
- lamt环境搭建
目录 lamt环境搭建 安装apache 安装mysql 安装tomcat 修改配置文件 lamt环境搭建 环境说明: 系统 IP 需要安装的服务 centos7 192.168.32.125 htt ...
- 串口通信—USB转串口
如何使用c库printf
- python分析BOSS直聘的某个招聘岗位数据
前言 毕业找工作,在职人员换工作,离职人员找工作……不管什么人群,应聘求职,都需要先分析对应的招聘岗位,岗位需求是否和自己匹配,常见的招聘平台有:BOSS直聘.拉钩招聘.智联招聘等,我们通常的方法都是 ...
- 90行代码让微信地球转起来,太酷了!(python实现)
1.微信地球 手机重启后打开微信的一瞬间,会看到一幅有名的图片,上面站着一个 张小龙 . 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手. ...
- windows 下部署 .netcore 到 windows service
接上一篇 <windows 下部署 .netcore 到 iis>,这一篇记录一下怎么将 Asp.Net Core 以 windows 服务的方式部署. 一.修改代码 其实也很简单,只要调 ...
- javascript函数的笔记
1.函数的概念 封装一段可以被重复调用执行的代码块来实现大量代码的重复使用 2.函数的使用分为两步:声明函数 和 调用函数 3.声明函数的关键字全部是小写 4.函数名一 ...
- Spring Cloud 之服务注册中心高可用
服务注册中心高可用 服务注册中心 eureka-server 高可用实施 版本 Spring Boot 版本 # Spring Boot 版本: <parent> <groupId& ...
- 剑指offer之字符串是否为数值
1. 题目 这是<剑指offer>上的一道题,刚开始觉得这是一道挺简单的题目,后来发现自己太年轻了,考虑的因素太少了,思考了而是分钟还是无从下手,看了作者的思路深深被他折服了,题目如下: ...
- C# ASP response.write()弹出提示框后页面布局被打乱
发现在使用了response.write后样式发生了变化,位置和字体都不正确.Response.Write("<script>alert(')</script>&qu ...