第6章 方法区 运行时常量池 类加载器

对象Object
里面有

Object{
  Class class;//所属的类
  Slot[] slots;//实例变量
}

方法区

运行时数据区的一块逻辑区域,由多个线程共享。
主要存放从class文件获取的类信息,类变量也存放在方法区中。
当Java虚拟机第一次使用某个类时,它会搜索类路径,找到相应的class文件,然后读取并解析class文件,把相关信息放进方法区。
至于方法区到底位于何处,是固定大小还是动态调整,是否参与垃圾回收,以及如何在方法区内存放类数据等,Java虚拟机规范并没有明确规定。

我放在ClassLoader里面

ClassLoader

public class MyClassLoader  {
    //依赖Classpath来搜索和读取class文件
    private Classpath classpath;

  //方法区 key是类的完全限定名
    private Map 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);

你可能感兴趣的:(第6章 方法区 运行时常量池 类加载器)