反射 p3 类加载

这篇具有很好参考价值的文章主要介绍了反射 p3 类加载。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

类加载

基本说明

反射机制是Java实现动态语言的关键,也就是通过反射实现类动态加载。

  1. 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强。
  2. 动态加载:运行时加载相关的类,如果运行时不用该类,即使不存在该类,也不会报错,降低了依赖性。
  • 代码演示:

    import java.util.*;
    import java.lang.reflect.*;
    
    public class ClassLoad_{
    	public static void main(String[] args) throws Exception{
    		Scanner scan = new Scanner(System.in);
    		String key = scan.next();
    
    		switch(key){
    			case "1":
    				Dog dog = new Dog();//静态加载,依赖性很强
    				dog.cry();
    				break;
    			case "2":
    				//反射 -> 动态加载
    				Class cls = Class.forName("Person");//加载Person类[动态加载]
    				Object o = cls.newInstance();
    				Method m = cls.getMethod("hi");
    				m.invoke(o);
    				System.out.println("OK");
    				break;
    			default:
    				System.out.println("do nothing....");
    		}
    
    	}
    }
    
    
    /* 未写Dog类时,DOS窗口运行结果,编译错误
    C:\Users\86199\Desktop>javac ClassLoad_.java
    ClassLoad_.java:11: 错误: 找不到符号
                                    Dog dog = new Dog();//静态加载,依赖性很强
                                    ^
      符号:   类 Dog
      位置: 类 ClassLoad_
    ClassLoad_.java:11: 错误: 找不到符号
                                    Dog dog = new Dog();//静态加载,依赖性很强
                                                  ^
      符号:   类 Dog
      位置: 类 ClassLoad_
    注: ClassLoad_.java使用了未经检查或不安全的操作。
    注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
    2 个错误
    */
    
    
    //因为 new Dog() 是静态加载,因此必须编写Dog类,否则在编译过程就会报错
    //Person类是动态加载,所以没有编写Person类在编译过程也不会报错,
    //只有在动态加载该类时才会报错
    
    class Dog{
    	public void cry(){
    		System.out.println("小狗汪汪叫");
    	}
    }
    
    
    /* 未写Person类时,DOS窗口运行结果,运行时报错
    C:\Users\86199\Desktop>java ClassLoad_
    1
    小狗汪汪叫
    ===============================================================
    C:\Users\86199\Desktop>java ClassLoad_
    2
    Exception in thread "main" java.lang.ClassNotFoundException: Person
            at java.net.URLClassLoader.findClass(Unknown Source)
            at java.lang.ClassLoader.loadClass(Unknown Source)
            at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
            at java.lang.ClassLoader.loadClass(Unknown Source)
            at java.lang.Class.forName0(Native Method)
            at java.lang.Class.forName(Unknown Source)
            at ClassLoad_.main(ClassLoad_.java:16)
    */
    
    
    class Person{
    	public void hi(){
    		System.out.println("hi....");
    	}
    }
    
    /* 写了Peson类后,DOS窗口运行结果
    C:\Users\86199\Desktop>java ClassLoad_
    1
    小狗汪汪叫
    =================================================
    C:\Users\86199\Desktop>java ClassLoad_
    2
    hi....
    OK
    */
    

类加载时机

  1. 当创建对象时(new),静态加载;
  2. 当子类被加载时,父类也加载,静态加载;
  3. 调用类中的静态成员时,静态加载;
  4. 通过反射,动态加载;

类加载流程

类加载流程图

  • 类加载过程图

    反射 p3 类加载

  • 类加载各阶段完成的任务

    反射 p3 类加载

类加载五个阶段

  1. 加载阶段(Loading)

    JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象;

  2. 连接阶段(Linking)

    1. 验证(Verification):

      • 目的:是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全;
      • 包括:文件格式验证(是否以魔数 oxcafebabe 开头)、元数据验证、字节码验证和符号引用验证;
      • 可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机加载的时间;
    2. 准备(Preparation):

      JVM 会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0、0L、null、false等)。这些变量所使用的内存都将在方法区中进行分配。

      package com.hspedu.classload_;
      
      /**
       * @author: 86199
       * @date: 2023/6/2 21:19
       * @description: 说明类加载夹的连接阶段(Linking)-准备(Preparation)
       */
      public class ClassLoad02 {
      }
      
      class A{
          //属性-字段-成员变量
          //分析类加载阶段的连接阶段(Linking)-准备,属性是如何处理的
          //1. n1是实例属性,不是静态变量,因此在准备阶段是不会分配内存的
          //2. n2是静态属性,分配内存,n2 默认初始化为0,而不是20,20是在连接阶段之后的初始化阶段进行的
          //3. n3是static final 是常量
          public int n1 = 1;
          public static int n2 = 2;
          public final static int n3 = 3;
      }
      
    3. 解析(Resolution):虚拟机将常量池内的符号引用替换为直接引用的过程。

  3. 初始化(Initialization):

    • 到初始化阶段,才是真正的开始执行类中定义的Java程序代码,此阶段是执行()方法的过程;

    • ()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并;

    • 虚拟机会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕;

      源码:

      反射 p3 类加载

    案例演示:文章来源地址https://www.toymoban.com/news/detail-602770.html

    package com.hspedu.classload_;
    
    /**
     * @author: 86199
     * @date: 2023/6/2 22:19
     * @description: 演示类加载——初始化阶段(Initialization)
     */
    public class ClassLoad03_ {
        static {
            System.out.println("ClassLoad03_ 静态代码块被执行");
        }
        public static void main(String[] args) throws ClassNotFoundException {
            //1. Loading:加载B类,并生成B类的Class对象
            //2. Linking:num = 0
            //3. Initialization:
            //      依次收集类中所有的静态变量和静态代码块中的语句入clinit()中,并合并
            /*
                clinit(){
                    System.out.println("B 静态代码块被执行");
                    //num = 300;
                    num = 100;
                }
                合并:num = 300, num = 100  --> num = 100
             */
    //        new B();//也会使B类加载,但是B类加载只会执行一遍
    //        System.out.println(B.num);//直接使用B类的静态属性,也会导致B类加载
    
            //看看类加载时,是有同步机制控制的
            /*
                protected Class<?> loadClass(String name, boolean resolve)
                    throws ClassNotFoundException
                {
                    synchronized (getClassLoadingLock(name)) {
                    //拿到一个同步锁,正因为有这个机制,才能保证某个类在内存中只有一份Class对象
                    }
                }
             */
            Class<?> aClass = Class.forName("B");
        }
    }
    
    class B{
        static {
            System.out.println("B 静态代码块被执行");
            num = 300;
        }
    
        static int num = 100;
    
        public B() {//构造器
            System.out.println("B() 构造器被执行...");
        }
    }
    
    

到了这里,关于反射 p3 类加载的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java笔记040-反射/反射机制、Class类

    目录 反射(reflection) 一个需求引出反射 反射机制 Java反射机制原理图 Java反射机制可以完成 反射相关的主要类 反射机制的优点和缺点 反射调用优化-关闭访问检查 Class类 基本介绍 代码解释部分 类加载方法 应用实例:Class02.java 获取Class类对象 代码解释部分 哪些类型有Class对象

    2024年02月09日
    浏览(49)
  • C#的反射机制

    当谈到C#的反射机制时,它提供了一种 动态 地在运行时获取和操作类型信息的能力。通过反射,可以 在编译时未知的情况下 ,使用类型信息来创建对象、调用方法、访问属性和字段等。下面是一些反射机制的重要概念和用法: Type 类型:Type 类型表示在代码中定义的类型(

    2024年02月10日
    浏览(54)
  • 什么是反射机制

    1.什么是类对象: 所有的类,都存在一个类对象,这个类对象用于提供类本身的信息,比如有几种构造方法, 有多少属性,有哪些普通方法。 比方有一个Hero类:类对象就是用于描述这种类,都有什么属性,什么方法的。 获取类对象有3种方式 Class.forName Hero.class new Hero().get

    2024年02月05日
    浏览(40)
  • Java的反射机制

    Java 的反射机制允许在程序运行期间,借助反射 API 获取类的内部信息,并能直接操作对象的内部属性及方法。 Java 反射机制提供的功能: 在运行时,使用反射分析类的能力,获取有关类的一切信息(类所在的包、类实现的接口、标注的注解、类的数据域、类的构造器、类的

    2024年02月02日
    浏览(42)
  • C# 反射机制详解

    Reflection,中文翻译为反射。 这是.Net中获取运行时类型信息的方式。 官方定义: 审查元数据并收集关于它的类型信息的能力。 元数据(编译以后的最基本数据单元) 就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义

    2024年02月07日
    浏览(45)
  • Java反射、代理机制

    官方解释:反射允许对封装类的字段、方法和构造方法的信息进行编程访问。 虚拟机加载类文件后,会在方法区生成一个类对象,包含了类的结构信息,如字段、方法、构造方法等。反射是一种能够在程序运行时动态访问、修改类对象中任意属性的机制(包括private属性)。

    2024年02月10日
    浏览(49)
  • Java反射机制深入详解

    一.概念 反射就是把Java的各种成分映射成相应的Java类。 Class类的构造方法是private,由JVM创建。 反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示

    2024年02月06日
    浏览(45)
  • Java的反射机制(2)

    目录 Class类基本介绍 Class类的常用方法 如何获取class类对象 哪些类型有Class对象 Class类基本介绍 在Java语言中,每个对象都有一个运行时类,即其所属的类。而这个运行时类在Java中是以Class类的实例形式存在的,该Class类实例就是所谓的Class对象。Class类表示一个类或接口的元

    2024年02月08日
    浏览(39)
  • Java反射机制是什么?

    Java 反射机制 是 Java 语言的一个重要特性。 在学习 Java 反射机制前,大家应该先了解两个概念,编译期和运行期。 编译期 是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成 class 文件的过程。编译期只是做了一些翻译功能,并没有把

    2024年02月12日
    浏览(38)
  • 【注释和反射】类加载的过程

    继上一篇博客【注释和反射】获取class类实例的方法-CSDN博客 目录 三、类加载的过程 例子 在Java虚拟机(JVM)中,类加载是一个将类的字节码文件从文件系统或其他来源加载到JVM的内存中,并将其转换为类或接口的过程。类加载的过程主要可以分为三个步骤:加载(Loading)、

    2024年04月25日
    浏览(16)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包