《剑指JVM》——第19章1——加载类——类装载子系统1

🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。

✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!

🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客

🔥温馨提示:划到文末发现专栏彩蛋   点击这里直接传送

🔥本篇概览:详细讲解了加载类——类装载子系统1🌈⭕🔥


【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】


🔥 《剑指JVM》序言-CSDN博客

🔥 《剑指JVM》全书-CSDN博客


🌈章节引出

前一篇章:

我们知道 class 文件是存放在磁盘上的,如果想要在JVM中使用class文件,需要将其加载至内存当中。前面我们已经讲解了class文件的结构,本章将详细介绍class 文件加载到内存中的过程。

🌈章节速览


概述


        在 Java 中数据类型分为基本数据类型和引用数据类型。

        基本数据类型由 JVM预先定义可以直接被用户使用引用数据类型则需要执行类的加载才可以被用户使用。

        Java虚拟机规范中规定,class文件加载到内存,再到类卸载出内存会经历(7个阶段,分别是加载、验证、准备、解析、初始化、使用和卸载,其中(验证、准备和解析3个阶段统称为链接,整个过程称为类的生命周期如图: 


加载阶段


1.加载完成的操作


        所谓加载,简而言之就是将Java类的class文件加载到机器内存,并在内存中构建Java类的原型,也就是类模板对象【Class对象】。所谓类模板对象,其实就是Java类在JVM内存中的快照。JVM 将从 class 文件中解析出的常量池、类字段、类方法等信息存储到类模板对象中
        JVM 在运行期可以通过类模板对象获取Java类中的任意信息【反射机制】,能够访问 Java类中的成员变也能调用 java 方法,反射机制便是基于这一基础,(如果JVM 没有将 Java 类的声明信息存储起来,则 JVM 在运行期也无法使用反射。

        在加载类时,JVM 必须完成以下3件事情:


(1)通过类的全名,获取类的二进制数据流。

(2)解析类的二进制数据流为方法区内的数据结构(Java类模型)。

(3)创建java.lang.Class类的实例,作为方法区中访问类数据的入口。 


2 二进制流的获取方式


JVM 可以通过多种途径产生或获得类的一进制数据流,例如:

(1)通过文件系统读入一个后缀为.class的文件(最常见)。

(2)读入jar、zip 等归档数据包,(提取类文件)

(3)事先存放在数据库中的类的二进制数据。

(4)使用类似于 HTTP 之类的协议通过网络加载。

(5)在运行时生成一段 Class)的二进制信息.【反射】


        获取到二进制信息流后,JVM会处理信息,最终转化为一个java.lang.Class的实例,作为最终方法区内访问类数据的接口。


3.类模型与Class实例的位置

1.类模型的位置

        加载的类在 JVM 中创建相应的类结构,类结构会存储在方法区中。

2. Class实例的位置

         类载器将 class 文件加载至方法区后,会在堆中创建一个 Java.lang.Class 对象用来封装类位于方法区内的数据结构该Class 对象是在加载类的过程中创建的每个类都对应有一个 Class类型的对象【每个类都要封装】。

        类模型和 Class 实例的位置对应关系如图 19-2 所示:


        外部可以通过访问代表Order类的Class对象来获取 Order类的数据结构。java.lang.Class 类的构造方法是私有的,只有JVM能够创建java.lang.Class实例,也是访问类型元数据的入口.

      【构造方法私有的用法——防止其他类创建对象】。     

        也是实现反射的关键数据。通过 Class 类提供的接口,可以获得目标类所关联的 class 文件中具体的数据结构、方法、字段等信息

      


         3.1实战通过Class类获取类信息

         如代码所示,展示了如何通过 java.lang.Class 类获取方法信息:

【这份代码也是求解类名求解其方法的模版代码】

package com.itheima.classloadsystem;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class LoadingTest {
    public static void main(String[] args) {
        try {
            // 获取java.lang.Class类的Class对象
            Class<?> clazz = Class.forName("java.lang.Class");

            // 获取当前运行时类声明的所有方法
            Method[] ms = clazz.getDeclaredMethods();

            // 遍历每个方法,打印其修饰符、返回值类型、方法名和参数列表
            for (Method m : ms) {
                // 获取方法的修饰符
                String mod = Modifier.toString(m.getModifiers());
                System.out.print(mod + " ");

                // 获取方法的返回值类型
                String returnType = m.getReturnType().getSimpleName();
                System.out.print(returnType + " ");

                // 获取方法名
                System.out.print(m.getName() + "(");

                // 获取方法的参数列表
                Class<?>[] ps = m.getParameterTypes();
                if (ps.length == 0) {
                    System.out.print(')');
                } else {
                    for (int i = 0; i < ps.length; i++) {
                        char end = (i == ps.length - 1) ? ')' : ',';
                        // 获取参数的类型
                        System.out.print(ps[i].getSimpleName() + end);
                    }
                }
                System.out.println();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}


通过上面的代码可以直接获取到 Class类的方法信息,运行结果如下:

D:\environment\JDK21\jdk-21.0.2\bin\java.exe -javaagent:D:\IDEA2024.1.4\ideaIU-2024.1.4.win\lib\idea_rt.jar=49244:D:\IDEA2024.1.4\ideaIU-2024.1.4.win\bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath D:\代码\JVM\GC\target\classes com.itheima.classloadsystem.LoadingTest
public String getName()
private void checkPackageAccess(SecurityManager,ClassLoader,boolean)
public static Class forName(String,boolean,ClassLoader)
private static Class forName(String,boolean,ClassLoader,Class)
public static Class forName(Module,String)
private static Class forName(Module,String,Class)
public static Class forName(String)
private static Class forName(String,Class)
private static native Class forName0(String,boolean,ClassLoader,Class)
public String toString()
public Module getModule()
public ProtectionDomain getProtectionDomain()
public native boolean isAssignableFrom(Class)
public native boolean isInstance(Object)
public native int getModifiers()
public native boolean isInterface()
public native boolean isArray()
public native boolean isPrimitive()
public native boolean isHidden()
public native Class getSuperclass()
public Object cast(Object)
public volatile OfField componentType()
public Class componentType()
 ClassLoader getClassLoader0()
public Optional describeConstable()
public Class getComponentType()
public boolean isAnnotation()
public boolean isEnum()
public boolean isRecord()
public TypeVariable[] getTypeParameters()
public ClassLoader getClassLoader()
private void checkMemberAccess(SecurityManager,int,Class,boolean)
private static ReflectionFactory getReflectionFactory()
private Constructor getConstructor0(Class[],int)
public Object newInstance()
private native String initClassName()
private ClassRepository getGenericInfo()
private Class elementType()
public Class[] getInterfaces()
private Class[] getInterfaces(boolean)
private ReflectionData reflectionData()
private native Class[] getInterfaces0()
public boolean isMemberClass()
public boolean isLocalClass()
public boolean isAnonymousClass()
private int getClassAccessFlagsRaw()
private EnclosingMethodInfo getEnclosingMethodInfo()
private GenericsFactory getFactory()
private static Class toClass(Type)
public Class getEnclosingClass()
private Method[] privateGetDeclaredMethods(boolean)
private static boolean arrayContentsEq(Object[],Object[])
private native Object[] getEnclosingMethod0()
private Constructor[] privateGetDeclaredConstructors(boolean)
private native Class getDeclaringClass0()
public boolean isUnnamedClass()
private String getSimpleName0()
public String getSimpleName()
private String getSimpleBinaryName()
private String getCanonicalName0()
public String getCanonicalName()
private boolean isLocalOrAnonymousClass()
public boolean isSynthetic()
private boolean isTopLevelClass()
private native String getSimpleBinaryName0()
private boolean hasEnclosingMethodInfo()
private Field[] privateGetPublicFields()
private static Field[] copyFields(Field[])
private Method[] privateGetPublicMethods()
private static Method[] copyMethods(Method[])
private static Constructor[] copyConstructors(Constructor[])
private Field getField0(String)
private Method getMethod0(String,Class[])
private String methodToString(String,Class[])
private native Class[] getDeclaredClasses0()
private Field[] privateGetDeclaredFields(boolean)
private native RecordComponent[] getRecordComponents0()
private static Field searchFields(Field[],String)
private static Method searchMethods(Method[],String,Class[])
private String resolveName(String)
private boolean isOpenToCaller(String,Class)
public InputStream getResourceAsStream(String)
public URL getResource(String)
 ProtectionDomain protectionDomain()
private native ProtectionDomain getProtectionDomain0()
public String getPackageName()
private ReflectionData newReflectionData(SoftReference,int)
private native String getGenericSignature0()
static byte[] getExecutableTypeAnnotationBytes(Executable)
private native Field[] getDeclaredFields0(boolean)
private static void addAll(Collection,Field[])
private native Constructor[] getDeclaredConstructors0(boolean)
private native Method[] getDeclaredMethods0(boolean)
private MethodList getMethodsRecursive(String,Class[],boolean)
private static native boolean desiredAssertionStatus0(Class)
public boolean desiredAssertionStatus()
private native boolean isRecord0()
 Object[] getEnumConstantsShared()
public transient Method getMethod(String,Class[])
 Map enumConstantDirectory()
private String cannotCastMsg(Object)
private AnnotationData annotationData()
public boolean isAnnotationPresent(Class)
private AnnotationData createAnnotationData(int)
native byte[] getRawAnnotations()
native ConstantPool getConstantPool()
 boolean casAnnotationType(AnnotationType,AnnotationType)
native byte[] getRawTypeAnnotations()
private native Class getNestHost0()
public Class getNestHost()
private native Class[] getNestMembers0()
public String descriptorString()
private native Class[] getPermittedSubclasses0()
private static void checkPackageAccessForPermittedSubclasses(SecurityManager,ClassLoader,Class[])
public Class[] getPermittedSubclasses()
private native int getClassFileVersion0()
private native int getClassAccessFlagsRaw0()
public Class arrayType()
public volatile OfField arrayType()
private boolean isDirectSubType(Class)
private static native void registerNatives()
public String toGenericString()
static String typeVarBounds(TypeVariable)
 Object getClassData()
public Type getGenericSuperclass()
public Package getPackage()
public Type[] getGenericInterfaces()
public Set accessFlags()
public native Object[] getSigners()
native void setSigners(Object[])
public Method getEnclosingMethod()
public Constructor getEnclosingConstructor()
public Class getDeclaringClass()
public String getTypeName()
public Class[] getClasses()
public Field[] getFields()
public Method[] getMethods()
public Constructor[] getConstructors()
public Field getField(String)
public transient Constructor getConstructor(Class[])
public Class[] getDeclaredClasses()
public Field[] getDeclaredFields()
public RecordComponent[] getRecordComponents()
public Method[] getDeclaredMethods()
public Constructor[] getDeclaredConstructors()
public Field getDeclaredField(String)
public transient Method getDeclaredMethod(String,Class[])
transient List getDeclaredPublicMethods(String,Class[])
public transient Constructor getDeclaredConstructor(Class[])
static native Class getPrimitiveClass(String)
public Object[] getEnumConstants()
public Class asSubclass(Class)
public Annotation getAnnotation(Class)
public Annotation[] getAnnotationsByType(Class)
public Annotation[] getAnnotations()
public Annotation getDeclaredAnnotation(Class)
public Annotation[] getDeclaredAnnotationsByType(Class)
public Annotation[] getDeclaredAnnotations()
 AnnotationType getAnnotationType()
 Map getDeclaredAnnotationMap()
public AnnotatedType getAnnotatedSuperclass()
public AnnotatedType[] getAnnotatedInterfaces()
public boolean isNestmateOf(Class)
public Class[] getNestMembers()
public boolean isSealed()
private int getClassFileVersion()
private static Class[] lambda$getPermittedSubclasses$2(int)
private boolean lambda$getPermittedSubclasses$1(Class)
private static String lambda$methodToString$0(Class)

Process finished with exit code 0


4.数组类的加载


        创建数组类的情况稍微有些特殊,数组类由JVM 在运行时根据需要直接创建,所以数组类没有对应class 文件,也就没有二进制形式,所以也就无法使用类加载器去创建数组类。但数组的元素类型仍然需要依靠类加载器去创建。创建数组类的过程如下。

(1)如果数组的元素类型是引用类型,那么就遵循定义的加载过程递归加载和创建数组的元素类型,JVM 使用指定的元素类型和数组维度来创建新的数组类。

(2)如果数组的元素是基本数据类型,比如int类型的数组,由于基本数据类型是由JVM领先定义的,所以也不需要类加载,只需要关注数组维度即可。
如果数组的元素类型是引用类型,数组类的可访问性就由元素类型的可访问性决定。否则数组类的可访问性将被缺省定义为 public



💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖

热门专栏推荐

🌈🌈计算机科学入门系列                     关注走一波💕💕

🌈🌈CSAPP深入理解计算机原理        关注走一波💕💕

🌈🌈微服务项目之黑马头条                 关注走一波💕💕

🌈🌈redis深度项目之黑马点评            关注走一波💕💕

🌈🌈JAVA面试八股文系列专栏           关注走一波💕💕

🌈🌈JAVA基础试题集精讲                  关注走一波💕💕   

🌈🌈代码随想录精讲200题                  关注走一波💕💕


总栏

🌈🌈JAVA基础要夯牢                         关注走一波💕💕  

🌈🌈​​​​​​JAVA后端技术栈                          关注走一波💕💕  

🌈🌈JAVA面试八股文​​​​​​                          关注走一波💕💕  

🌈🌈JAVA项目(含源码深度剖析)    关注走一波💕💕  

🌈🌈计算机四件套                               关注走一波💕💕  

🌈🌈数据结构与算法                           ​关注走一波💕💕  

🌈🌈必知必会工具集                           关注走一波💕💕

🌈🌈书籍网课笔记汇总                       关注走一波💕💕         



📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!

  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值