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.(()为我手 ...
随机推荐
- 11-13 模块_collections(不太重要)&time&random&os
random:随机数模块 os:和操作系统打交道的模块 sys:和Python解释器打交道的模块 序列化模块:Python中的数据类型和str转换的模块 http://www.cnblogs.com/ ...
- PHP substr_count() 函数
实例 计算 "world" 在字符串中出现的次数: <?php高佣联盟 www.cgewang.comecho substr_count("Hello world. ...
- Virtuoso 中的窗口_1
https://www.cnblogs.com/yeungchie/ hiDisplayAppDBox(简单弹出一个字符串,Tips) prog((TipsForm) hiDisplayAppDBox ...
- 笨办法学python 第四版 中文pdf高清版|网盘下载内附提取码
笨办法学 Python是Zed Shaw 编写的一本Python入门书籍.适合对计算机了解不多,没有学过编程,但对编程感兴趣的朋友学习使用.这本书以习题的方式引导读者一步一步学习编 程,从简单的打印一 ...
- 畅购商城(五):Elasticsearch实现商品搜索
好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 畅购商城(一):环境搭建 畅购商 ...
- Pytest单元测试框架:插件-allure-pytest环境搭建并在本地生成一个测试报告
之前写了allure-pytest的官方文档啃的内容,有些交流的朋友,实践起来没什么头绪,所以就有了这篇文章,也给自己填个坑 第一步:搭建Allure.JDK环境 1. 搭建JDK环境 不装jdk你会 ...
- [vue] computed 和 method
计算属性 计算属性只有在它的相关依赖发生改变时才会重新取值 Method method每次渲染的时候都会被执行 举一个栗子 <template>...<div> <p& ...
- Chrome-AdGuard 无与伦比的广告拦截扩展
一款无与伦比的广告拦截扩展,对抗各式广告与弹窗. AdGuard 广告拦截器可有效的拦截所有网页上的所有类型的广告,甚至是在 Facebook.Youtube 以及其他万千网站上的广告! AdGuar ...
- Windows-快速预览文件-QuickLook
开源.免费的文件快速预览工具, 支持图片.文档.音视频.代码文本.压缩包等多种格式. 获得 Mac OS 空格键快速预览文件相同的体验 效果图 文件夹 音视频 浏览 压缩包,文本 支持的格式: 图片: ...
- Java中增强一个类的几种方法
今天有人问我怎么增强一个类的功能.博客刚好没东西,今天就讲讲增强类. 增强的手段有三种类型: 1.继承或者实现接口:特点是被增强对象不能变,增强的内容不能变. 2.装饰着模式:特点是被增强对象可变,但 ...