对象Object
里面有
Object{
Class class;//所属的类
Slot[] slots;//实例变量
}
方法区
运行时数据区的一块逻辑区域,由多个线程共享。
主要存放从class文件获取的类信息,类变量也存放在方法区中。
当Java虚拟机第一次使用某个类时,它会搜索类路径,找到相应的class文件,然后读取并解析class文件,把相关信息放进方法区。
至于方法区到底位于何处,是固定大小还是动态调整,是否参与垃圾回收,以及如何在方法区内存放类数据等,Java虚拟机规范并没有明确规定。
我放在ClassLoader里面
ClassLoader
public class MyClassLoader {
//依赖Classpath来搜索和读取class文件
private Classpath classpath;
//方法区 key是类的完全限定名
private Map<String, Class> classInfoMap=new HashMap<>();
public Class loadClass(String className){
Class class = classInfoMap.get(className);
if (class==null){
classInfo= ......
classInfoMap.put(className,class);
}
return class;
}
}
类的加载大致可以分为3个步骤:
- 1.找到class文件并把数据读取到内存;
byte[] data;
try {
data = classpath.readClass(name);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("java.lang,ClassNotFoundException");
}
- 2.解析class文件,生成虚拟机可以使用的类数据,并放入方法区;
JClass classInfo = defineClass(data);
private JClass defineClass(byte[] data) {
//byte[] -> classFile ->class
JClass jClass = parseClass(data);
//并把其父类和接口也加载
jClass.interfaces = resolveInterfaces(jClass.getInterfaceNames());
jClass.superClass = resolveSuperClass(jClass.getSuperClassName());
//放入方法区
classInfoMap.put(jClass.getName(),jClass);
return jClass;
}
- 3.链接:验证和准备
link(Class class ) {
verify(class)
prepare(class)
}
prepare(JClass classInfo) {
//数实例field ,给每个实例field 编号 set一个slotId,总数存class
calcInstanceFieldSlotId(class);
//同上,这次是static Field,在class存一个这个数量的数组Object[] staticVars;
calcStaticFieldSlotId(class);
//给final static的field赋值,
//这些field的属性里面有常量池index是初值,
// 按其slotId放入类的staticVars
allocAndInitStaticVars(class);
}
类信息
JClass {
///////////////////////////////////////////直接copy来classFile
@Getter(AccessLevel.NONE)
private int accessFlags;// uint16 类的访问标志
//完全限定名,具有java/lang/Object的形式
private String name;// thisClassName
private String superClassName;
private String[] interfaceNames;
private RuntimeConstantPool runtimeConstantPool;//存放运行时常量池指针
private Field[] fields;
private Method[] methods;
/////////////////////////////////////////////////////////类加载时加工填充的
public MyClassLoader classLoader;//加载时保留加载器引用
public JClass superClass;
public JClass[] interfaces;
public int instanceSlotCount;
public int staticSlotCount;
public Object[] staticVars;
}
对象
{
JClass jClass;//所属的类
Object[] slots;//实例field的值
}
Field
{
//类成员都有的部分
protected int accessFlags ;//classFile复制
protected String name;//classFile复制
public String descriptor;//classFile复制
protected JClass jClass;//所属的类
int constValueIndex ;//classFile得 在属性里 字段的初始值index
//static是类的staticVars的id 实例field是对象里面slots的id
private int slotId ;//类加载时计算
}
Method
{
//类成员都有的部分
protected int accessFlags ;//classFile复制
protected String name;//classFile复制
public String descriptor;//classFile复制
protected JClass jClass;//所属的类
//来自Code的属性
private int maxStack ;
private int maxLocals ;
private byte[] code ;
}
运行时常量池
用classFile里的常量池 转的 index不变 没有就空着
classFile里的常量池 | 运行时常量池 |
---|---|
数字(i l f d) | 原样 |
UTF8 | |
STRING(引用UTF8) | 字符串 |
ClASS(引用UTF8) | 类引用(类名,使用类[能拿类加载器]) |
NAME_AND_TYPE(引用UTF8) | |
FIELD_REF(引用ClASS,NAME_AND_TYPE) | field引用(类引用,名,描述) |
METHOD_REF(引用ClASS,NAME_AND_TYPE) | method引用(类引用,名,描述) |
INTERFACE_METHOD_REF(引用ClASS,NAME_AND_TYPE) | method引用(类引用,名,描述) |
classFile里的常量池有所属类的引用 , 每个常量都有对常量池本身的引用
类和对象相关指令
new
class=frame.method.class.runtimeConstantPool(操作数index);
newObject={
class
slot[class.instanceSlotCount]//instanceSlotCount是类加载时按实例field数出来的
};
frame.operandStack.push(newObject);
PutStatic
field=frame.method.class.runtimeConstantsPool[指令操作数index]
field.class.staticVars[field.slotId]
GetStatic
field=frame.method.class.runtimeConstantsPool[指令操作数index]
frame.operandStack.push(field.class.staticVars[field.slotId])
Putfield
stack=frame.operandStack;
val=stack.pop;
object=stack.pop;
field=frame.method.class.runtimeConstantsPool[指令操作数index];
object.slot[field.slotId]=val;
Putfield
field=frame.method.class.runtimeConstantsPool[指令操作数index];
stack=frame.operandStack;
object=stack.pop;
stack.push(object.slot[field.slotId]);
Instanceof
class=frame.method.class.runtimeConstantPool(操作数index);
stack=frame.operandStack;
object=stack.pop;
if(object.class isInstanceOf class){
stack.push(1);
}else{
stack.push(0);
}
Checkcast
object=stack.pop()
stack.push(object);
class=frame.method.class.runtimeConstantPool(操作数index);
if(!object.class isInstanceOf class){
throw new ClassCastException();
}
用于
if (xxx instanceof ClassYYY) {//Instanceof
yyy = (ClassYYY) xxx;//Checkcast
// use yyy
}
Ldc
Object constant = frame.method().class().runtimeConstantPool[index]
operandStack.push(constant);