前言 那一年,呼延十又回想起被加载顺序支配的恐惧,笔试题上,好几个类,几个方法,几个输出语句,让你按照顺序写出输出.我真的是有一句…. 但是呢,我们还是有了解一下的必要的,在编码过程中有许多的应用. 由于B类有父类,因此先加载A类. 加载A类的静态代码块,输出A-----static. 加载B类的静态变量,调用了方法,输出B----- static func. 加载B类的静态代码块,输出B----- static. 加载A类的普通变量,private int i = aFunc();由于调用了方法,因此输出A----- default. 加载A类的构造方法,输出A----- constructor. 加载B类的普通变量,调用了方法,输出B----- default. 加载B类的构造方法,输出了B----- constructor. 静态变量,静态代码块的加载顺序只和代码编写的顺序有关. 普通变量及构造方法,顺序一定是先普通变量,再构造方法的. 说好的应用呢 其实我目前对这个知识点应用最多的就是静态代码块.
先准备3个逐层继承的类User1,User2,User3 User2继承User1,User3继承User2 分别在类中准备构造函数,普通初始化块,静态代码块 public class User1 { 的普通初始化块 User2的构造函数调用 User3的普通初始化块 User3的构造函数调用 静态代码块------------->普通初始化块--------------->构造函数 构造函数先执行父类, 再执行子类的原理: Java默认在无参的构造函数中会执行super(),则会递归执行构造函数,因而先执行父类再执行子类 有参构造的情况: 先扩展代码: public class User1 { 但如果对代码稍作修改,在有参构造前添加super(anme),即可执行父类的有参构造了 public User3(String aname){ super(aname); this.name = aname; System.out.println("User3的有参构造函数调用"); } image.png 无参的构造函数虽然是隐试调用,但是如果子类继承你的类,而你没有无参构造函数
语音版: Java类的初始化顺序这个问题经常出现在面试题中,这个面试题设计的知识有类、对象、static关键字、初始化函数、类的加载顺序,咱们一个一个来说。 类: 类描述了具有相同特性(数据元素)和行为(功能)的对象集合,也是一个数据类型。比如说动物,它有重量、大小的特征(数据元素),也有移动、吃的行为(功能)。 对象: 对象是具有状态、行为和标识的是上面类的一个实例。 它是属于类不属于对象。 初始化函数: 也就是构造器,构造器名称必须与类名完全相同,没有返回值。没有参数的构造器叫做默认构造器,你在不重载情况下都是调用的默认构造器。 类的加载顺序: static块和对象:无论写在类的前面还是后面都会先执行,多个静态块或者对象执行顺序与写的顺序一致,写在前面的先执行; 非静态块和对象:按照在类中写的先后顺序执行; 初始化函数;
在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来定制类的加载方式。 为什么要自定义类加载器? 隔离加载类 修改类加载的方式 扩展加载源 防止源码泄漏 用户自定义类加载器实现步骤: 开发人员可以通过继承抽象类ava.1ang.ClassLoader类的方式,实现自己的类加载器,以满足一些特殊的需求 在JDK1.2之前,在自定义类加载器时,总会去继承ClassLoader类并重写1oadClass()方法,从而实现自定义的类加载类,但是在JDK1.2之后已不再建议用户去覆盖1oadclass()方法 ,而是建议把自定义的类加载逻辑写在findclass()方法中 在编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URIClassLoader类,这样就可以避免自己去编写findclass( )方法及其获取字节码流的方式,使自定义类加载器编写更加简洁。
类内容的几个概念 a. 静态代码块 b. 构造代码块 c. 构造函数 d. 普通代码块 2. 类实例化的执行顺序 a. 代码 b. 执行结果 ---- 1. 类内容的几个概念 a. 静态代码块 静态代码块在类被加载的时候执行,并且只执行一次,它的优先级是最高的,在构造代码块和构造函数和main方法之前。如果有多个静态代码块,按代码编写的顺序执行。 静态代码块只能在类里,不能在方法里,对于静态方法:在类加载的时候,静态方法也已经加载了,但是我们必须要通过类名或者对象名才能访问,也就是说相比于静态代码块,静态代码块是主动运行的,而静态方法是被动运行的 且普通代码块的执行顺序和书写顺序一致。 2. 类实例化的执行顺序 a. 执行结果 根据上面的代码可以看到,我们的main方法、构造代码块、静态代码块都是没有顺序的放置,但是在输出结果里可以看到他们的执行是有固定顺序的,看下图: 在开发过程中可以根据具体业务去定义如何使用静态代码块
blockA blockB blockA B blockA blockA blockB C blockB blockB blockA D blockB blockA blockB 考点:考察求职者对类的加载顺序的掌握 出现频率:★★★★★ 【面试题分析】 1.首先,需要明白类的加载顺序。 (1) 父类静态对象和静态代码块 (2) 子类静态对象和静态代码块 (3) 父类非静态对象和非静态代码块 (4) 父类构造函数 (5) 子类 非静态对象和非静态代码块 (6) 子类构造函数 其中:类中静态块按照声明顺序执行 ,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的) 2.因而,整体的执行顺序为 public static Test t1 = new Test();
基于相关的调研, 我的理解为, 对于一个URI请求, 浏览器会按照下面的请求和执行顺序进行: 一个线程对DOM进行下载(也就是html, 而不去管html中的外部资源) 另外一个线程会开始分析已经下载的 3: 6 Opera 9.26: 4 Opera 9.5 beta: 4 Safari 3.0.4 Mac/Windows: 4 IE 7: 2 IE 8: 6 所以请根据这个实际情况来思考上面的下载顺序 然后我们看执行顺序(js的执行, css的应用等): 只要浏览器"看到了"了js代码,它就会执行 浏览器是从下到下,一行一行地执行 如果js代码位于一个函数或者对象中,则只有当函数或者对象被调用时才会执行 而所谓的direct code(不处于函数或者对象中的代码),则会从上到下顺序执行 当css文件下载完成时, 相应的样式也会应用到DOM上 onload或者jquery的$(document).ready 你可能会奇怪如果js可以并行下载,那么可能位于DOM下面的代码会先执行, 首先可以肯定的是 即使下面的js先完成下载,也不会影响到整体的从上到下的执行顺序,浏览器会维护这种顺序的关系, chrome的这种方式也是未来浏览器的一种趋势
6,如果存在继承关系,则父类先加载,再加载子类。 引用关系 加载器和Class对象:双向引用 在类加载器的内部实现中,用一个Java集合来存放所加载类的引用。 另一方面,一个Class对象总是会引用它的类加载器。 类的卸载 由Java虚拟机自带的类加载器所加载的类,在虚拟机的生命周期中,始终不会被卸载。 前面介绍过,Java虚拟机自带的类加载器包括根类加载器、扩展类加载器和系统类加载器。 Java虚拟机本身会始终引用这些类加载器,而这些类加载器则会始终引用它们所加载的类的Class对象,因此这些Class对象始终是可触及的。 由用户自定义的类加载器加载的类是可以被卸载的。 【总结】 (1) 启动类加载器加载的类型在整个运行期间是不可能被卸载的(jvm和jls规范); (2) 被系统类加载器和标准扩展类加载器加载的类型在运行期间不太可能被卸载,因为系统类加载器实例或者标准扩展类的实例基本上在整个运行期间总能直接或者间接的访问的到
一、类生命周期概览Java类从加载到卸载经历7个阶段:加载 → 2. 验证 → 3. 准备 → 4. 解析 → 5. 初始化 → 6. 使用 → 7. 准备 类加载过程中 分配内存并设置静态变量默认值 初始化 首次主动使用类时 执行静态代码块和显式初始化 二、初始化阶段执行顺序 // 不触发接口初始化new InterfaceImpl.T(); // 触发接口初始化执行特点:接口初始化不要求父接口初始化首次访问接口的非常量静态字段才会初始化六、类加载顺序总结 6.1 完整流程图开始↓父类静态变量/块(按代码顺序)↓子类静态变量/块(按代码顺序)↓父类实例变量/块(按代码顺序)↓父类构造器↓子类实例变量/块(按代码顺序)↓子类构造器结束6.2 记忆口诀静父静子先静态 c; }}掌握类加载顺序原理,能够帮助开发者:合理设计类结构优化程序启动性能准确定位初始化相关BUG深入理解框架启动机制
A null B sub C base 考点:考察求职者对类的执行步骤问题的理解 出现频率:★★★★★ 【面试题分析】 new Sub();在创造派生类的过程中首先创建基类对象,然后才能创建派生类。 创建基类即默认调用Base()方法,在方法中调用callName()方法,由于派生类中存在此方法,则被调用的callName()方法是派生类中的方法,此时派生类还未构造,所以变量baseName的值为null ---- 一般的程序执行步骤为:父类静态代码块->父类非静态代码块->子类静态代码块->父类构造函数->子类非静态代码块->子类构造函数。 该选项中父类引用指向子类对象,首先执行父类非静态代码块,baseName 初始化,然后执行父类构造方法,发现此时直接调用了方法,又因为子类重写了该方法,所以执行子类的callName()方法,而此时子类非静态代码块还没初始化
A 父类B静态代码块->父类B构造函数->子类A静态代码块->父类B非静态代码块->子类A构造函数->子类A非静态代码块 B 父类B静态代码块->父类B构造函数->父类B非静态代码块->子类A静态代码块 ->子类A构造函数->子类A非静态代码块 C 父类B静态代码块->子类A静态代码块->父类B非静态代码块->父类B构造函数->子类A非静态代码块->子类A构造函数 D 父类B构造函数->父类B静态代码块 ->父类B非静态代码块->子类A静态代码块->子类A构造函数->子类A非静态代码块 考点:考察求职者对类的加载顺序的掌握 出现频率:★★★★★ 【面试题分析】 按照先后顺序: 1,静态先于非静态代码库执行 (静态代码块随着类的加载而加载,初始化只执行一次) 2,父类先于子类 3,非静态代码块优于构造函数执行 所以参考答案是 (C)
一、背景: 在面试中,在java基础方面,类的加载顺序经常被问及,很多时候我们是搞不清楚到底类的加载顺序是怎么样的,那么今天我们就来看看带有继承的类的加载顺序到底是怎么一回事? 三、测试结果 由测试结果可知:程序首先加载类,然后再对类进行初始化。 加载类的顺序为:先加载基类,基类加载完毕后再加载子类。 初始化的顺序为:先初始化基类,基类初始化完毕后再初始化子类。 最后得出类加载顺序为:先按照声明顺序初始化基类静态变量和静态代码块,接着按照声明顺序初始化子类静态变量和静态代码块,而后按照声明顺序初始化基类普通变量和普通代码块,然后执行基类构造函数,接着按照声明顺序初始化子类普通变量和普通代码块 对于本测试中的执行顺序为:先初始化static的变量,在执行main()方法之前就需要进行加载。 关于继承的初始化机制,首先执行含有main方法的类,观察到Zi类含有基类Fu,即先加载Fu类的static变量,再加载Zi类的static变量。
概述 Spring Boot的启动加载顺序是一个涉及多个步骤和组件的过程。 以下是按照主要阶段和关键步骤划分的Spring Boot启动加载顺序的概述: 启动准备阶段: 装载核心启动器类:org.springframework.boot.SpringApplication /(项目根路径) classpath:/config/(类路径下的config文件夹) classpath:/(类路径) 外部配置文件的加载方式: 命令行参数:可以直接在启动命令后添加启动参数。 如果使用Spring Boot的自动配置机制,那么会有一系列自动配置类根据条件进行加载和配置。 具体的启动加载顺序可能会因Spring Boot版本和具体配置而有所不同,但整体流程是类似的。 通过清晰地了解Spring Boot的启动加载顺序,可以更好地理解和控制应用的启动过程,以及如何进行配置和扩展。
之前说过Java中类的加载顺序,这次看完继承部分,就结合继承再来说说类的加载顺序。 继承的加载顺序 由于static块会在首次加载类的时候执行,因此下面的例子就是用static块来测试类的加载顺序。 因此当创建C的时候,会自动加载C继承的B和依赖的D,然后B又会加载继承的A。只有A加载完,才能顺利的加载B;BD加载完,才能加载C。这就是类的加载顺序了。 ,静态成员类的对象,会优先加载;而普通成员类的对象则是使用的时候才回去加载。 第四点,类对象的创建以及静态块的访问,都会触发类的加载。
这就是虚拟机的类加载。 类加载概念 ? 上图是类加载和卸载的整个过程示意图,其中验证、准备、解析统称为连接阶段。 加载、验证、准备、初始化和卸载这5个阶段开始的顺序是固定的,但是解析阶段在某些情况下可以在初始化以后再进行。 类加载-加载阶段 加载是类加载的第一个阶段,加载阶段的主要目标是: 通过一个类的全限定名来获取定义此类的二进制字节流 将字节流的静态信息结构转换为方法区(元数据区)的运行时数据结构 在内存中生成一个代表这个类的 非数组类的加载需要通过类加载器实现,既可以使用系统的提供的引导类加载,也可以使用用户自定义的类加载器去完成,关于类加载器后续我会单独写一篇文章来介绍,并且实现我们自己的一个类加载器。 本期类加载的加载阶段就介绍到这,下期我们会讲解类加载的连接阶段,我们下期再见!!!
学习编程思想 1 package com.test.java.classs; 2 3 /** 4 * Created by Administrator on 2015/12/7. 5 * 在类的内部 ,变量定义的顺序决定了初始化的顺序。
SpringBoot内部配置加载顺序 简介:本文通过案例讲解,SpringBoot的内部配置的加载顺序。 概述 程序启动的时候,配置文件的加载顺序,优先级,由高到低为: file:.
:解释器会默认加载一些 modules,除了sys.builtin_module_names 列出的内置模块之外,还会加载其他一些标准库,都存放在sys.modules字典中。 综上所述,搜索的一个顺序是:sys.modules 缓存 -> sys.path0 即当前目录查找 -> sys.path1:路径查找。 同时发现,模块被加载的时候,其中非函数或类的语句,例如 print('hello')、name=michael等,是会在 import的时候,默认就执行了。 4.交互式执行环境的查找顺序交互执行环境,解释器会自动把当前目录加入到sys.path,这一点和直接执行文件是一样的,但是这种方式下,sys.path0 是存储的当前目录的相对路径,而不是绝对路径。 8.总结Python 通过查找 sys.path 来决定包的导入,Python解释器启动时加载的模块缓存 > 同级目录 > sys.path1:。
你知道jvm是怎么加载类的么? 类的初始化顺序你有了解么? 我出一个面试题,你能答出来么? ? "); } } 大家可以把上面的代码拷贝到编辑器上面,执行下看看和自己预期的结果是否一致,这段代码基本上可以展示出了类加载和初始化顺序,给大家看下结果 ? 可以看出如果有继承父类的话,会优先去初始化父类。遵循这样一个顺序 ? ? 得到counter1和counter2分别为1和0 到此,面试已经结束,我们来结合理论知识总结下jvm类加载和初始化顺序。 java类加载分为五个过程,如图: ? 类加载顺序 1 加载 这阶段主要是加载class文件到JVM中,class文件可以是来自本地,也可以是一段二进制流:jvm主要做了如下工作: 1)通过classloader 获取XXX.class
在这五个阶段中,加载、验证、准备和初始化这四个阶段发生的顺序是确定的,而解析阶段则不一定,它在某些情况下可以在初始化阶段之后开始,这是为了支持Java语言的运行时绑定(也成为动态绑定或晚期绑定)。 另外注意这里的几个阶段是按顺序开始,而不是按顺序进行或完成,因为这些阶段通常都是互相交叉地混合进行的,通常在一个阶段执行的过程中调用或激活另一个阶段。 ,所以说父类如果定义static块的话,一定比子类先执行 如果一个类或接口中没有static变量的赋值操作和static{}语句块,那么 不会被JVM生成 static变量的赋值操作和static{}语句块合并的顺序是由语句在源文件中出现的顺序所决定的 看到一段代码,很有意思 /** * 测试类加载及初始化顺序问题 * Created by jack01.zhu on 2018/9/28. */ public class ClassInit { ,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成加载请求(它管理的范围之中没有这个类)时,子加载器才会尝试着自己去加载 ?