在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高级特性——反射机制(第二篇)的更多相关文章

  1. Java高级特性——反射机制(第一篇)

    ——何为动态语言,何为静态语言?(学习反射知识前,需要了解动态语言和静态语言) 动态语言 >是一类在运行时可以改变其结构的语言,例如新的函数.对象.甚至是代码可以被引进,已有的函数可以被删除或者 ...

  2. Java高级特性——反射机制(第三篇)

    获取类运行时的结构 通过反射获取运行时类的完整结构 Field.Method.Constructor.Superclass.Interface.Annotation >实现的全部接口 >所 ...

  3. Java高级特性——反射机制(完结)——反射与注解

    按照我们的学习进度,在前边我们讲过什么是注解以及注解如何定义,如果忘了,可以先回顾一下https://www.cnblogs.com/hgqin/p/13462051.html. 在学习反射和注解前, ...

  4. Java高级特性——反射

    感谢原文作者:peter_RD_nj 原文链接:https://www.jianshu.com/p/9be58ee20dee 注意:同一个类在JVM中只存在一份字节码对象 概述 定义 JAVA反射机制 ...

  5. java的反射机制(第二篇)

    本文转载自:http://c.biancheng.net/cpp/html/1781.html 要理解RTTI在Java中的工作原理,首先必须知道类型信息在运行时是如何表示的,这项工作是由“Class ...

  6. JAVA高级特性反射和注解

    反射: 枚举反射泛型注解.html34.3 KB 反射, 主要是指通过类加载, 动态的访问, 检测和修改类本身状态或行为的一种能力, 并能根据自身行为的状态和结果, 调整或修改应用所描述行为的状态和相 ...

  7. Java高级特性—反射和动态代理

    1).反射 通过反射的方式可以获取class对象中的属性.方法.构造函数等,一下是实例: 2).动态代理 使用场景: 在之前的代码调用阶段,我们用action调用service的方法实现业务即可. 由 ...

  8. Java高级特性 第5节 序列化和、反射机制

    一.序列化 1.序列化概述 在实际开发中,经常需要将对象的信息保存到磁盘中便于检索,但通过前面输入输出流的方法逐一对对象的属性信息进行操作,很繁琐并容易出错,而序列化提供了轻松解决这个问题的快捷方法. ...

  9. 浅说Java中的反射机制(一)

    在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...

随机推荐

  1. PHP fputcsv() 函数

    定义和用法 fputcsv() 函数将行格式化为 CSV 并写入一个打开的文件中. 该函数返回写入字符串的长度.如果失败,则返回 FALSE. 语法 fputcsv(file,fields,seper ...

  2. PHP imageaffinematrixconcat - 连接两个矩阵

    imageaffinematrixconcat — 连接两个矩阵.高佣联盟 www.cgewang.com 语法 array imageaffinematrixconcat ( array $m1 , ...

  3. C++程序员容易走入性能优化误区!对此你怎么看呢?

    有些C++ 程序员,特别是只写C++ 没有写过 Python/PHP 等慢语言的程序员,容易对性能有心智负担,就像着了魔一样,每写3 行代码必有一行代码因为性能考虑而优化使得代码变形(复杂而晦涩). ...

  4. luogu P1452 [USACO03FALL]Beauty Contest G /【模板】旋转卡壳

    LINK:旋转卡壳 如题 是一道模板题. 容易想到n^2暴力 当然也能随机化选点 (还真有人过了 考虑旋转卡壳 其实就是对于某个点来说找到其最远的点. 在找的过程中需要借助一下个点的帮助 利用当前点到 ...

  5. luogu P2525 Uim的情人节礼物 其之壱

    LINK:Uim的情人节礼物·其之壱 壱 古代通壹 常在日文中出现. 完全可以使用STL -->prev_permutation来解决. 不过我简单了解了一下康托展开. 这是一个一个排列对应一个 ...

  6. .net core编写转发服务

    我有个小伙伴问我,他需要写一个转发服务的他有很多功能要通过他的服务转发~ 技术栈又不一定asp.net core,我就想起泥水老前辈的BeetleX.FastHttpApi 中午午休,折腾了一会儿前辈 ...

  7. 【HNOI2012】永无乡 题解(并查集+线段树合并)

    题目链接 给定一张含$n$个点$m$条边的无向图,每个点有一个重要指数$a_i$.有两种操作:1.在$x$和$y$之间连一条边:2.求$x$所在连通块中重要程度第$k$小的点. ----------- ...

  8. 解惑4:java是值传递还是引用传递

    一.概述 曾经纠结了很久java的参数传递方式是什么样的,后面粗略的了解了一鳞半爪以后有了大概的印象:"传参数就是值传递,传对象就是引用传递",后面进一步查找了相关资料和文章以后, ...

  9. 解决使用rollup构建ECharts过程中遇到的问题

    1.ECharts官方文档 参考:自定义构建 ECharts - ECharts Documentation 2.解决问题 改动一: // line.js // 引入 echarts 主模块. // ...

  10. Visual Studio安装

    2017 安装的时候,一直显示,安装成功但是有告警. 解决方法: 将visual studio 2017 installer进行卸载,然后安装hw的ios 不能确保下次也可以成功