当前位置: 首页 > news >正文

笔记:Java面向对象编程 第10章 类的生命周期

一、JVM 的生命周期

JVM 结束的时机:

程序结束;程序因为异常或错误终止;System.exit();操作系统终止JVM


二、类生命周期的开始

步骤:

(1)、加载 

(2)、连接:包括验证(即确保其正确性)、准备(即为静态变量分配内存、初始化默认值)、解析(将符号引用转换为直接引用)

(3)、初始化:为静态变量赋予初始值


2.1  类的加载

将class文件的二进制数据读入方法区,在堆区创建一个Class对象。

注意:Class的数据结构在方法区,Class对象在堆区


类加载器在加载过程中,如果遇到class缺失或损坏,不会马上报错而是等到首次主动使用该class时候才报错,如果一直不使用该class就不报错。


2.2 类的验证

验证的内容:检查结构、语义、字节码、二进制兼容


2.3 类的准备

为静态变量分配内存,赋予初值。例子:

private static int a=1;
private static long b;
int c=3;

static
{
    b=3;
}

此时为a分配4个字节的内存空间,赋默认值 0,为b分配8个字节空间,赋默认值 0;而 c是实例变量,此时不会分配空间

 

2.4、类的解析

符号引用解析为直接引用


2.5、类的初始化

在静态变量声明处或者静态代码块中初始化。

注意:(1)、初始化一个类的时候,会先初始化其父类,但不会初始化其接口。初始化一个接口,不会初始化其父接口。

(2)、声明时候不会初始化,使用到的时候才初始化

MyObject  obj;   // 不会初始化MyObject
obj  = new MyObject :  // 此时才初始化MyObject

2.6、类初始化的时机


主动使用的时候初始化:访问静态变量;访问静态方法;创建类的实例(包括new语句、反射、clone、反序列化);调用反射方法;初始化子类;JVM启动类。


不会初始化的情况:

(1)、使用编译时常量不会初始化

对于final static 变量,如果编译时候就能算出其值,则为编译时常量。

public final static int a=2*3+4;                 //编译时常量,首次使用不会导致类的初始化
public final static int b=(int)Math.random();    //不是编译时时常量,首次使用会导致类的初始化


(2)、接口:使用类不会初始化其实现的接口,使用子接口不会初始化其父接口


interface IAction {}

class Action implements IAction {}

interface IAction2 extends IAction{}

调用 Action 、IAction2 的静态变量、静态方法都不会初始化 IAction


(3)、程序访问的静态变量或静态方法的确在本类时候,才会初始化,如果在父类,则只初始化父类

class Father
{
      public static int a=9;
      public static int hehe() {}
}

class Son extents Father
{
}

如果调用 Son.a 和 Son.hehe(), 不会初始化Son类,只会初始化Father 类


(4)、ClassLoader.loadClass() 是加载,不会初始化;Class.forName() 是初始化

Class<?>  clazz = myClassLoader.loadClass("className")   //不会初始化,

Class<?>  clazz = Class.forName("className")    // 会初始化



三、类加载器

1、父亲委托机制

类加载器classLorderA加载类 时候,会先委托父加载器classLorderB去加载,父加载器classLorderB 又去委托其父加载器classLorderC 。。。直到根加载器,根加载器一层一层往下选,找到某个能加载的classLoader,则加载之。

加载器委托关系:



Bootstrap加载器  null:(加载JDK核心类库)

Extension加载器 sun.misc.Launcher$ExtClassLoader:(加载 lib/ext/ 下类库)

System 加载器 sun.misc.Launcher$AppClassLoader:(加载classpath中其他类库)



注意:加载器之间的父子关系是包装关系,而不是继承关系,代码如下:

ClassLoader fatherLoader = new MyClassLoader();
ClassLoader sonrLoader = new ClassLoader(fatherLoader);


父亲委托机制的好处:

(1)、防止不可靠的代码替换由父加载器加载的可靠代码,例子:java.lang.Object 总是由Bootstrap加载器加载,用户定义的加载器不能加载 java.lang.Object  类来进行不安全的操作。

(2)、同一个类文件,由两个不同的类加载器分别加载为实例classA、classB,此时classA 和 classB 仍然被看做不同的class,因为其类加载器不一样。

(3)、假如用户定义一个类java.lang.MyObject,企图用java.lang,MyObject 去访问JDK核心包java.lang.*下面的包可见的成员(类、变量、方法),这是不可能成功的。因为核心类java.lang.* 由Bootstrap加载器加载,而java.lang.MyObject 由System加载器或者用户自定义加载器加载,加载器不同则属于不同的运行时包,只有属于同一运行时包的成员才可以相互访问包可见成员。

 

2、创建自定义加载器

继承 ClassLoader 类,覆盖 findClass(String name) 方法。

类加载器之间的委托关系是包装关系,而不是继承关系,代码如下:

ClassLoader fatherLoader = new MyClassLoader();
ClassLoader sonrLoader = new ClassLoader(fatherLoader);


多个加载器之间的命名空间关系如下:

(1)、同一命名空间之间的类相互可见

(2)、子加载器的加载的类可以看到父加载器的加载的类,父加载器的加载的类不能看到子加载器的加载的类

(3)、若两个类加载器之间没有直接或间接的父子关系,则它们各自加载的类相互不可见

(4)、两个不同命名空间的类相互不可见的时候,可以通过反射访问对方实例的属性和方法。


3、java.net.URLClassLoader 

java.net.URLClassLoader 属于用户加载器,而不是System加载器,虽然其包含在核心包中,通过URL从本地或远程加载类


四、类的卸载

Bootstrap、Extension、System加载器所加载的类,永远不会被卸载,因为JVM始终引用这些类加载器,而这些类加载器又始终引用其加载的Class对象

用户自定义加载器所加载的类,在Class对象不再被引用时,会被卸载。注意:

(1)、一个类的实例总是引用代表这个类的Class对象,如instance.getClass() 总能返回其Class 对象。故要卸载Class,其所有的instance 必须也不再被引用。

(2)、类加载内部有一个集合保全了其所加载的所有Class的引用,故要卸载Class,其类加载器也必须被卸载。

(3)、以下三个变量c1、c2、c3是同一个Class 对象

Class<?>  c1 = mypackage.MyClass.class;
Class<?>  c2 = (new mypackage.MyClass()).getClass();
Class<?>  c3 = Class.forName("mypackage.MyClass");

Class<?> c4 = myClassLoader,loadClass("mypackage.MyClass") 

则不一定与c1、c2、c3 相同,因为可能不是同一个类加载器








转载于:https://www.cnblogs.com/leeeee/p/7276183.html

相关文章:

  • 锁定应用,解锁应用,锁卡,解卡,更改密码指令
  • Matlab的部分文件操作
  • 如何管理?
  • 系统时钟和硬件时钟同步
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • zblog2.0博客建站视频教程
  • Product Google的十大设计原则
  • 如何修复U盘提示被写保护的问题
  • 浅谈Docker(一)
  • 使用SharedPreferences存储数据
  • [JDBC-1] JDBC Base Template
  • Ant编译环境
  • 中转server
  • sl4a
  • SGU[107] 987654321 problem
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • C++类中的特殊成员函数
  • canvas 绘制双线技巧
  • Flannel解读
  • Redux 中间件分析
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • tweak 支持第三方库
  • Vue ES6 Jade Scss Webpack Gulp
  • 从零搭建Koa2 Server
  • 如何设计一个比特币钱包服务
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • #pragma multi_compile #pragma shader_feature
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (C语言)输入一个序列,判断是否为奇偶交叉数
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (二)pulsar安装在独立的docker中,python测试
  • (论文阅读笔记)Network planning with deep reinforcement learning
  • (四)c52学习之旅-流水LED灯
  • (一)基于IDEA的JAVA基础10
  • (转载)PyTorch代码规范最佳实践和样式指南
  • *p++,*(p++),*++p,(*p)++区别?
  • .bat批处理出现中文乱码的情况
  • .naturalWidth 和naturalHeight属性,
  • .net core webapi 大文件上传到wwwroot文件夹
  • .NET 跨平台图形库 SkiaSharp 基础应用
  • .NET/C# 利用 Walterlv.WeakEvents 高性能地中转一个自定义的弱事件(可让任意 CLR 事件成为弱事件)
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • @cacheable 是否缓存成功_让我们来学习学习SpringCache分布式缓存,为什么用?
  • [ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决
  • [2013AAA]On a fractional nonlinear hyperbolic equation arising from relative theory
  • [ACM] hdu 1201 18岁生日
  • [ai笔记4] 将AI工具场景化,应用于生活和工作
  • [android] 请求码和结果码的作用
  • [bzoj1912]异象石(set)
  • [C#] 基于 yield 语句的迭代器逻辑懒执行
  • [ICCV2017]Neural Person Search Machines
  • [java进阶]——方法引用改写Lambda表达式
  • [LeetCode] Longest Common Prefix 字符串公有前序