深入java虚拟机里说,无论何时java虚拟机遇到某些指向被引用类新的字段或者方法的符号引用,且被引用的类型的初始装载并非是初始装载引用类型的同一个类装载器,虚拟机就会在列表上加一个约束,虚拟机在解析符号引用的时候必须检查当前已经能够装载的所有约束。
从上面的说明来看,加约束的前提是存在多个类加载器,并且发生了引用关系,下面写一个测试案例。
首先定义一个普通的类:
public class Constraint {
}
定义一个普通的B类
public class B {
public void test(Constraint l) {
Constraint ll = new Constraint();
}
}
一个普通的A类,其中首先产生一个Constraint类,然后加载B类,通过B去传递一个实例到B的test方法
public class A {
public A() {
Constraint constraint = new Constraint();
B b = new B();
b.test(constraint);
}
}
然后是2个classLoader,一个classLoader不会发生类加载约束。
classLoader2:
public class ClassLoader2 extends URLClassLoader {
/**
* @param urls
* @param parent
*/
public ClassLoader2(URL[] urls) {
super(urls);
}
}
另一个classLoader,这个类有些特殊,如果发现加载的类是B的话,直接委托给classLoader1去加载
public class ClassLoader1 extends URLClassLoader {
private URL[] urls = null;
/**
* @param urls
*/
public ClassLoader1(java.net.URL[] urls) {
super(urls);
this.urls = urls;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals("B")) {
return new ClassLoader2(urls).loadClass("B");
} else {
return super.loadClass(name);
}
}
}
一个启动类:
public class Start {
public static void test()
{
A a = new A();
}
}
最后我们装配起来:
public class Main {
public static void main(String[] args) throws Exception {
URL binPath = Main.class.getClassLoader().getResource(".");
File parent = new File(binPath.toURI()).getParentFile();
URL cp1 = new File(parent, "init").toURI().toURL();
ClassLoader1 cl1 = new ClassLoader1(new URL[] { cp1 });
Class<?> clazz = cl1.loadClass("Start");
Method method = clazz.getMethod("test", null);
method.invoke(clazz.newInstance(), null);
}
}
以上就是所有的代码了。我们来分析一下流程。
首先将编译好的A,B,Constraint,start类方法init目录下,防止他们被系统类加载器加载到。
启动是从Main类的main方法开始的,启动classLoader1去加载start类,调用Start的test方法。Strat类里用到的所有的类都会由ClassLoader1去加载,也就是说Start里的A是有classLoader1加载的。
A初始化的时候需要用到Constraint类,此时发现classLoader1是可以加载Constraint的,所有他将加入到classLoader1的命名空间里去。下一步需要加载B,此时发现classLoaer1直接将B委托给了classLoader2去加载,这个时候就出现了多个类加载器了,前提条件1已经满足了。classLoader2成功加载了B。此时我们应该想到,仅仅出现了多个类加载器,并没有发生引用关系,所有虚拟机不会去增加加载约束,事实上也是这样的。我们可以给Main方法启动的时候增加一个虚拟机参数:-XX:+TraceLoaderConstraints ,这个参数适用于jdk1.6之后。如有有发生加载约束的情况,他会打印到标准输出。
下一步就是要调用B.test(constraint)方法了,此时引用类A,用classLoader1加载,被引用的类B用classLoader2加载,两者发生了引用关系,此时虚拟机就应该加上一个约束关系,这个约束关系就是
[Adding new constraint for name: Constraint, loader[0]: ClassLoader1, loader[1]: ClassLoader2 ]
classLoader1加载的Constraint类必须和ClassLoader2加载的Constraint指向同一个数据类型。
下面接着走到了B的test方法里面,B会加载Constraint,因为B的加载器是classLoader2,所以依然会用ClassLoader2去加载Constraint,Constraint 的初始类加载器是classLoader2,此时就会违反了类加载约束。因为classLoader1里已经加载了类Constraint,假设classLoader2里也能加载成功,那么classLoader2加载的类对classLoader1是可见的(因为委托关系,定义类加载器加载的类对初始类加载器可见),那么classLoader1里就会有2个Constraint,对于classLoader1来说就不知道应该引用哪个了,所以增加加载约束是必须的。运行到这个代码段的时候就报错了:
Caused by: java.lang.LinkageError: loader constraint violation: loader (instance of ClassLoader2) previously initiated loading for a different type with name "Constraint"
如果是这样的话,那么如果B的test里不去调用new Constraint是不是就不会违反约束了呢?
那我们注释掉B的调用试试
public class B {
public void test(Constraint l) {
// Constraint ll = new Constraint();
}
}
运行的结果我们可以发现,加载约束已经装载了,但是没有发生loader constraint violation,原因就是没有用到Constraint类,仅仅是增加了约束,一旦有用到的时候,就会报错
[Adding new constraint for name: Constraint, loader[0]: ClassLoader1, loader[1]: ClassLoader2 ]
下面再看一下深入java虚拟机的介绍。
当解析一个包含在<C,L1>中的符号引用(它指向的是类<D,L2>中声明的类型T的字段)时,虚拟机必须产生下列装载约束,TL1=TL2
下面我们修改一下B类为:
public class B {
Constraint cc = new Constraint();
public void test(Constraint l) {
// Constraint ll = new Constraint();
}
}
或者修改B为:
public class B extends Constraint{
public void test(Constraint l) {
// Constraint ll = new Constraint();
}
}
在B类的成员变量里增加一个Constraint cc= new Constraint()的调用。
运行条件不变,运行的过程中classLoader1会首先加载Constraint类(A类的调用),而classLoader2加载B的时候也会加载一个Constraint类,同一个类被不同的类加载器加载到了内存中,这是允许的,没有任何问题。但是执行到A类的b,test(constraint)的时候,他们建立了引用关系,此时要增加一个加载约束,下面是运行输出
[Failed to add constraint for name: Constraint, loader[0]: ClassLoader1, loader[1]: ClassLoader2, Reason: the class objects presented by loader[0] and loader[1] are different ]
他发现要加载的Constraint是不一样的类型,于是增加约束的时候就失败了,直接抛了异常:
Caused by: java.lang.LinkageError: loader constraint violation: when resolving method "B.test(LConstraint;)V" the class loader (instance of ClassLoader1) of the current class, A, and the class loader (instance of ClassLoader2) for resolved class, B, have different Class objects for the type Constraint used in the signature
at A.<init>(A.java:9)
at Start.test(Start.java:12)
... 5 more
B期待的是classLoader2的Constrant,而A传给B的确是classLoaer1的Constraint,这两个不是一个类型。
以上都属于测试结果和个人的分析,不代表实际的运行原理,欢迎批评指正错误。
附上测试代码。
分享到:
相关推荐
Synopsys Timing Constraints and Optimization User Guide Timing Constraints(时序约束)是数字集成电路设计中的一种重要技术,用于描述和约束数字电路的时序行为。 Synopsys Timing Constraints and ...
airflow的安装文件constraints-3.8.txt
### Xilinx Constraints Guide详解 #### 一、引言 Xilinx公司是全球领先的可编程逻辑器件供应商之一,其产品广泛应用于通信、消费电子、汽车、工业控制等多个领域。随着技术的发展,Xilinx不断推出高性能的FPGA...
在"predictive control with constraints"这一主题中,我们将深入探讨如何在满足特定约束条件下进行有效的预测控制。 预测控制的核心是预测模型,它可以是基于动态方程、状态空间模型或者数据驱动的模型。这个模型...
airflow的安装文件constraints-3.6.txt
airflow的安装文件constraints-3.7.txt
airflow的安装文件constraints-3.9.txt
Predictive_Control_with_Constraints
关键词“Constraints”指的是算法设计中必须考虑的限制条件,如时间限制、预算限制等。这些约束条件对算法的搜索空间和最终路径的选择有着决定性的影响。而“Path Searching”则是算法在给定的图或网络中寻找特定...
#### 标题:时序约束(Timing Constraints) **时序约束**在Xilinx FPGA设计中扮演着至关重要的角色,它确保了最终设计能够在目标工作频率下稳定运行。Xilinx时序约束用户指南(Timing Constraints User Guide)是...
大型数据集的处理对于度量学习提出了挑战,而"Large Scale Metric Learning from Equivalence Constraints"则是针对这一问题提出的一种解决方案。该代码实现,即"KISSME"(Key-Insight into Similarity Metric for ...
metric learnig
"Timing Constraints and Clock Tree Synthesis" Timing Constraints and Clock Tree Synthesis是指在数字电路设计中对时序约束和时钟树综合的研究和应用。时序约束是指在数字电路设计中对时钟信号的约束条件,以...
9. **扩展性**:NUnit具有良好的扩展性,可以通过编写自定义的约束(Constraints)和测试适配器来满足特定的测试需求。 10. **兼容性**:NUnit 2.51版本支持.NET Framework的多个版本,如.NET 2.0、3.0、3.5等,...
启动Tomcat时报错:Caused by: java.lang.LinkageError: loader constraints violated when linking javax/el/ExpressionFactory class 说明:原因是juel.jar, juel-engine.jar, juel-impl.jar包和Tomcat6.0中的el-...
### SSD7 Unit1 Skill Builder: Identifying Keys and Integrity Constraints B #### 客户表 (Customer) **主键(Primary Key, PK):** - **ID**: 每个客户都有一个唯一的标识符,用于区分不同的客户。这个字段是...
本节主要介绍如何从UCF(User Constraints File)迁移到XDC(Xilinx Design Constraints)格式,并对XDC约束的基本概念进行了概述。XDC约束文件提供了更灵活、更强大的方式来定义时序和物理约束,相比UCF具有更多的...
input constraints Ali Saberi School of Electrical Engineering and Computer Science Washington State University Pullman, WA 99164-2752 U.S.A. Fax: (509) 335-3818 E-mail: saberi@eecs.wsu.edu Anton A. ...