类加载时机
「加载」
将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在内存上创建一个java.lang.Class
对象用来封装类在方法区内的数据结构作为这个类的各种数据的访问入口。
「验证」
主要是为了确保class文件中的字节流包含的信息是否符合当前JVM的要求,且不会危害JVM自身安全,比如校验文件格式、是否是cafe baby魔术、字节码验证等等。
「准备」
为类变量分配内存并设置类变量(是被static修饰的变量,变量不是常量,所以不是final的,就是static的)初始值的阶段。这些变量所使用的内存在方法区中进行分配。比如
private static int age = 26;
类变量age会在准备阶段过后为 其分配四个(int四个字节)字节的空间,并且设置初始值为0,而不是26。
若是final的,则在编译期就会设置上最终值。
「解析」
JVM会在此阶段把类的二进制数据中的符号引用替换为直接引用。
「初始化」
初始化阶段是执行类构造器<clinit>()
方法的过程,到了初始化阶段,才真正开始执行类定义的Java程序代码(或者说字节码 )。比如准备阶段的那个age初始值是0,到这一步就设置为26。
「使用」
对象都出来了,业务系统直接调用阶段。
「卸载」
用完了,可以被GC回收了。
类加载器种类
「启动类加载器(Bootstrap ClassLoader)」
最顶层类加载器,他的父类加载器是个null,也就是没有父类加载器。负责加载jvm的核心类库,比如java.lang.*
等,从系统属性中的sun.boot.class.path
所指定的目录中加载类库。他的具体实现由Java虚拟机底层C++代码实现。
「扩展类加载器(Extension ClassLoader)」
父类加载器是Bootstrap ClassLoader。从java.ext.dirs
系统属性所指定的目录中加载类库,或者从JDK的安装目录的jre/lib/ext
子目录(扩展目录)下加载类库,如果把用户的jar文件放在这个目录下,也会自动由扩展类加载器加载。继承自java.lang.ClassLoader
。
「应用程序类加载器(Application ClassLoader)」
父类加载器是Extension ClassLoader。从环境变量classpath或者系统属性java.class.path
所指定的目录中加载类。继承自java.lang.ClassLoader
。
「自定义类加载器(User ClassLoader)」
除了上面三个自带的以外,用户还能制定自己的类加载器,但是所有自定义的类加载器都应该继承自java.lang.ClassLoader
。比如热部署、tomcat都会用到自定义类加载器。
补充:不同ClassLoader加载的文件路径配置在如下源码里写的:
// sun.misc.Launcher
public class Launcher {
// Bootstrap类加载器的加载路径,在static静态代码块里用的
private static String bootClassPath = System.getProperty("sun.boot.class.path");
// AppClassLoader 继承 ClassLoader
static class AppClassLoader extends URLClassLoader {
public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
// java.class.path
final String var1 = System.getProperty("java.class.path");
}
}
// ExtClassLoader 继承 ClassLoader
static class ExtClassLoader extends URLClassLoader {
public static Launcher.ExtClassLoader getExtClassLoader() throws IOException {
// java.ext.dirs
String var0 = System.getProperty("java.ext.dirs");
}
}
}
如果一个类加载器收到了类加载的请求,他首先会从自己缓存里查找是否之前加载过这个class,加载过直接返回,没加载过的话他不会自己亲自去加载,他会把这个请求委派给父类加载器去完成,每一层都是如此,类似递归,一直递归到顶层父类。
也就是Bootstrap ClassLoader
,只要加载完成就会返回结果,如果顶层父类加载器无法加载此class,则会返回去交给子类加载器去尝试加载,若最底层的子类加载器也没找到,则会抛出ClassNotFoundException
。
源码在java.lang.ClassLoader#loadClass(java.lang.String, boolean)
双亲委派模型
防止内存中出现多份同样的字节码,安全。
比如自己重写个java.lang.Object
并放到Classpath中,没有双亲委派的话直接自己执行了,那不安全。双亲委派可以保证这个类只能被顶层Bootstrap Classloader
类加载器加载,从而确保只有JVM中有且仅有一份正常的java核心类。如果有多个的话,那么就乱套了。比如相同的类instance of
可能返回false,因为可能父类不是同一个类加载器加载的Object。
Jdbc
Jdbc为什么要破坏双亲委派模型?
以前的用法是未破坏双亲委派模型的,比如Class.forName("com.mysql.cj.jdbc.Driver");
而在JDBC4.0以后,开始支持使用spi的方式来注册这个Driver,具体做法就是在mysql的jar包中的META-INF/services/java.sql.Driver
文件中指明当前使用的Driver是哪个,然后使用的时候就不需要我们手动的去加载驱动了,我们只需要直接获取连接就可以了。Connection con = DriverManager.getConnection(url, username, password );
首先,理解一下为什么JDBC需要破坏双亲委派模式,原因是原生的JDBC中Driver驱动本身只是一个接口,并没有具体的实现,具体的实现是由不同数据库类型去实现的。例如,MySQL的mysql-connector-*.jar
中的Driver类具体实现的。
原生的JDBC中的类是放在rt.jar
包的,是由Bootstrap加载器进行类加载的,在JDBC中的Driver类中需要动态去加载不同数据库类型的Driver类,而mysql-connector-*.jar
中的Driver类是用户自己写的代码,那Bootstrap类加载器肯定是不能进行加载的,既然是自己编写的代码,那就需要由Application类加载器去进行类加载。
这个时候就引入线程上下文件类加载器(Thread Context ClassLoader
),通过这个东西程序就可以把原本需要由Bootstrap类加载器进行加载的类由Application类加载器去进行加载了。
Tomcat
Tomcat为什么要破坏双亲委派模型?
因为一个Tomcat可以部署N个web应用,但是每个web应用都有自己的classloader,互不干扰。比如web1里面有com.test.A.class
,web2里面也有com.test.A.class
,如果没打破双亲委派模型的话,那么web1加载完后,web2在加载的话会冲突。
因为只有一套classloader,却出现了两个重复的类路径,所以tomcat打破了,他是线程级别的,不同web应用是不同的classloader。
重写loadClass
方法,别重写findClass
方法,因为loadClass
是核心入口,将其重写成自定义逻辑即可破坏双亲委派模型。
只需要继承java.lang.Classloader
类,然后覆盖他的findClass(String name)
方法即可,该方法根据参数指定的类名称,返回对应 的Class对象的引用。
采取破坏双亲委派模型的手段来实现热部署,默认的loadClass()
方法先找缓存,你改了class字节码也不会热加载,所以自定义ClassLoader,去掉找缓存那部分,直接就去加载,也就是每次都重新加载。
问题:输出结果是什么?
答案:编译报错。
原因:因为静态语句块中只能访问定义在静态语句块之前的变量,定义在他之后的 变量在前面的静态语句块中可以赋值,但是不能访问。
/**
* Description: 编译报错
*
* @author TongWei.Chen 2021-01-08 17:37:44
*/
public class Test1 {
static {
// 编译没报错
i = 2;
// 编译报错Illegal forward reference
System.out.println(i);
}
private static int i =1;
}
问题:输出结果是什么?
答案 :1、3
原因:因为类加载过程中会先准备类变量(也就是静态变量),准备阶段是赋初始值阶段,也就是test2=null,value1=0,value2=0
,然后进入初始化阶段的时候test2=new Test2()
,会执行构造器,结果是value1 = 1,value2 = 4
,然后执行value1和value2这两句,value1没变化,value2被重新赋值成了3,所以结果1和3。
public class Test2 {
private static Test2 test2 = new Test2();
private static int value1;
private static int value2 = 3;
private Test2() {
value1 ++;
value2 ++;
}
public static void main(String[] args) {
// 1
System.out.println(test2.value1);
// 3
System.out.println(test2.value2);
}
}
那如果把private static Test2 test2 = new Test2();
放到private static int value2 = 3;
下面的话结果就是1和4了。
public class Test3 {
private static int value1;
private static int value2 = 3;
private static Test3 test3 = new Test3();
private Test3() {
value1 ++;
value2 ++;
}
public static void main(String[] args) {
// 1
System.out.println(test3.value1);
// 4
System.out.println(test3.value2);
}
}
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/2iGaiOpxBIM3msAZYPUOnQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。