类加载和通过反射获取类的结构信息
  TEZNKK3IfmPf 2023年11月13日 32 0

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

1.静态加载:编译时加载相关的类,如果没有写出该类,则报错,依赖性太强

2.动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不报错,降低了依赖性

代码在com.stulzl.class_load_.包中

ClassLoad_

package com.stulzl.class_load_;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;

//类加载  719
public class ClassLoad_ {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入key");
        String key = scanner.next();
        switch(key){
            case "1":
                Dog dog = new Dog();//静态加载,依赖性很强,因为静态加载,所以必须写出Dog类,编译才能通过
                dog.cry();
                break;
            case "2":
                //反射->动态加载,不用写出这个类编译就能通过
                Class cls = Class.forName("com.stulzl.class_load_.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……");
        }
    }
}
//因为new Dog()是静态加载,因此必须编写Dog
//Person类是动态加载,所以,没有编写Person类也不会报错,只要有当动态加载该类时才会报错
class Dog{
    public void cry(){
        System.out.println("小狗汪汪叫……");
    }
}

class Person{
    public void hi(){
        System.out.println("小孩打招呼……");
    }
}

2. 类加载时机  719

1.当创建对象时(new) //静态加载

2.当子类被加载时,父类也加载//静态加载

3.调用类中的静态成员时//静态加载

4.通过反射//动态加载  例:Class.forName(" com.test.Cat"):

3. 类加载过程图  720

类加载和通过反射获取类的结构信息

4. 类加载各阶段完成任务  720

类加载和通过反射获取类的结构信息

4.1 加载阶段  721

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

类加载和通过反射获取类的结构信息

4.2 连接阶段-验证  721

1.目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。

2.包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据验证、字节码验证和符号引用验证

3. 可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。

4.3 连接阶段-准备  721

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

2.举例说明: ClassLoad02.java

代码在com.stulzl.class_load_02.

 ClassLoad02

package com.stulzl.class_load_02;

//我们说明一下列加载的链接阶段——准备  721
public class ClassLoad02 {
    public static void main(String[] args) {

    }
}
class A{
    //属性-成员变量-字段
    //分析类加载的链接阶段-准备 属性是如何处理
    //1. n1 是实例属性, 不是静态变量,因此在准备阶段,是不会分配内存
    //2. n2 是静态变量,分配内存 n2 是默认初始化 0 ,而不是 20
    //3. n3 是 static final 是常量, 他和静态变量不一样, 因为一旦赋值就不变 n3 = 30
    public int n1 = 10;
    public static int n2 = 20;
    public static final int n3 = 30;//提示final修饰的变量不允许被修改
}

4.4 连接阶段-解析  721

1.虚拟机将常量池内的符号引用替换为直接引用的过程。

2.举例说明:

类加载和通过反射获取类的结构信息

4.5 Initialization(初始化)  722

1.到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行< clinit> 0方法的过程。

2.  ()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,井进行合井。[举例说明ClassLoad03.java]

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

代码在com.stulzl.class_load_03

ClassLoad03

package com.stulzl.class_load_03;

//演示类加载-初始化阶段  722
public class ClassLoad03 {
    public static void main(String[] args) {

        //分析
        //1. 加载 B 类,并生成 B 的 class 对象
        //2. 链接——赋默认值 num = 0
        //3. 初始化阶段
        // 依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并合并
        /*
            clinit() {
                System.out.println("B 静态代码块被执行");
                num = 300;
                num = 100;
            }
            合并结果: num = 100
        */
        //new B();//类加载
        System.out.println(B.num);//100//如果直接使用类的静态属性,也会导致类的加载

        //看看加载类的时候,是有同步机制控制
        /*
        protected Class loadClass(String name, boolean resolve)
        throws ClassNotFoundException
        {
            //正因为有这个机制,才能保证某个类在内存中, 只有一份 Class 对象
            synchronized (getClassLoadingLock(name)) {
            //.... }
        }
        */
        B b = new B();
    }
}
class B {
    //代码块
    static {
        System.out.println("B 静态代码块被执行");
        num = 300;
    }
    static int num = 100;
    public B() {//构造器
        System.out.println("B() 构造器被执行");
    }
}

5. 通过反射获取类的结构信息

5.1 第一组: java.lang.Class 类     723

1. getName:获取全类名

2. getSimpleName:获取简单类名

3. getFields:获取所有public修饰的属性,包含本类以及父类的

4. getDeclaredFields:获取本类中所有属性

5. getMethods:获取所有public修饰的方法,包含本类以及父类的

6. getDeclaredMethods:获取本类中所有方法

7. getConstructors: 获取本类所有public修饰的构造器

8. getDeclaredConstructors:获取本类中所有构造器

9. getPackage:以Package形式返回包信息

10.getSuperClass:以Class形式返回父类信息

11.getInterfaces:以Class[]形式返回接口信息

12.getAnnotations:以Annotation[]形式返回注解信息

代码在com.stulzl.reflection_.包中

ReflectionUtils

package com.stulzl.reflection_;

import org.junit.jupiter.api.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

//演示如何通过反射获取列的结构信息  723
public class ReflectionUtils {
    public static void main(String[] args) {

    }
    //第一组
    @Test
    public void api_01() throws ClassNotFoundException {
        Class personCls = Class.forName("com.stulzl.reflection_.Person");
        //1. getName:获取全类名
        System.out.println(personCls.getName());//com.stulzl.reflection_.Person

        //2. getSimpleName:获取简单类名
        System.out.println(personCls.getSimpleName());//Person

        //3. getFields:获取所有public修饰的属性,包含本类以及父类的
        Field[] fields = personCls.getFields();
        for (Field field : fields) {//增强for循环
            System.out.println("本类以及父类的public属性"+field.getName());
        }

        //4. getDeclaredFields:获取本类中所有属性
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本类中所有属性"+declaredField.getName());
        }

        //5. getMethods:获取所有public修饰的方法,包含本类以及父类的
        Method[] methods = personCls.getMethods();
        for (Method method : methods) {
            System.out.println("本类以及父类的public方法"+method.getName());
        }

        //6. getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中所有方法"+declaredMethod.getName());
        }

        //7. getConstructors: 获取本类所有public修饰的构造器
        Constructor[] constructors = personCls.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("本类所有public修饰的构造器"+constructor);
        }

        //8. getDeclaredConstructors:获取本类中所有构造器
        Constructor[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println("获取本类中所有构造器"+ declaredConstructor);
        }

        //9. getPackage:以Package形式返回包信息
        System.out.println(personCls.getPackage());//com.stulzl.reflection_

        //10.getSuperClass:以Class形式返回父类信息
        Class superclass = personCls.getSuperclass();
        System.out.println(superclass);//com.stulzl.reflection_.A

        //11.getInterfaces:以Class[]形式返回接口信息
        Class[] interfaces = personCls.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println("接口信息"+anInterface);
        }

        //12.getAnnotations:以Annotation[]形式返回注解信息
        Annotation[] annotations = personCls.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("注解"+annotation);
        }

    }
}

class A{
    public String hobby;
    public void hi(){

    }
    //构造器
    public A(){}

}
interface IA{

}
interface IB{

}

@Deprecated  //注解
class Person extends A implements IA,IB{
    //属性
    public String name;
    protected int age;
    String job;
    private double sal;

    //构造器
    public Person(){}
    public Person(String name){}
    private Person(String name,int age){}

    //方法
    public void m1(){

    }

    protected void m2(){

    }

    void m3(){

    }

    private void m4(){

    }
}

5.2 第二组: java.lang.reflect.Field 类  724

1. getModifiers: 以int形式返回修饰符[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final 是16],public(1) + static (8) = 9

2. getType:以Class形式返回类型

3. getName:返回属性名

5.3 第三组: java.lang.reflect.Method 类  724

1. getModifiers:以int形式返回修饰符[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final是16]

2. getReturnType:以Class形式获取返回类型

3. getName:返回方法名

4. getParameterTypes:以Class[]返回参数类型数组

5.4 第四组: java.lang.reflect.Constructor 类  724

1. getModifiers:以int形式返回修饰符

2. getName:返回构造器名(全类名)

3. getParameterTypes:以Class[]返回参数类型数组

二三四组代码在com.stulzl.reflection_02

ReflectionUtils02

package com.stulzl.reflection_02;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

//通过反射获取类的结构信息
public class ReflectionUtils02 {
    public static void main(String[] args) {

    }

    @Test
    public void api_02() throws ClassNotFoundException {
        Class personCls = Class.forName("com.stulzl.reflection_02.Person");

        //第二组: java.lang.reflect.Field 类    724
        //4. getDeclaredFields:获取本类中所有属性
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本类中所有属性"+declaredField.getName()
                    //1. getModifiers: 以int形式返回修饰符[说明:默认修饰符是0,public 是1,
                    // private是2,protected是4,static是8,final 是16]
                    +" 该属性的修饰符="+declaredField.getModifiers()
                    //2. getType:以Class形式返回类型
            +" 给属性的类型="+declaredField.getType());
        }
        System.out.println("=========================");
        //第三组: java.lang.reflect.Method 类  724
        //6. getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中所有方法"+declaredMethod.getName()
                    //1. getModifiers:以int形式返回修饰符[说明:默认修饰符是0,public 是1,
                    // private是2,protected是4,static是8,final是16]
            +" 该方法的访问修饰符="+declaredMethod.getModifiers()
                    //2. getReturnType:以Class形式获取返回类型
            +" 该方法的返回类型="+declaredMethod.getReturnType());

            //4. getParameterTypes:以Class[]返回参数类型数组
            Class[] parameterTypes = declaredMethod.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.println("该方法的形参数组="+parameterType);
            }
        }
        System.out.println("===============");
        //第四组: java.lang.reflect.Constructor 类   724
        //8. getDeclaredConstructors:获取本类中所有构造器
        Constructor[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println("获取本类中所有构造器"+ declaredConstructor);

            //3. getParameterTypes:以Class[]返回参数类型数组
            Class[] parameterTypes = declaredConstructor.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.println("该构造器的形参数组="+parameterType);
            }
        }
    }
}
class A{
    public String hobby;
    public void hi(){

    }
    //构造器
    public A(){}

}
interface IA{

}
interface IB{

}

@Deprecated  //注解
class Person extends A implements IA, IB {
    //属性
    public String name;
    protected static int age;//修饰符值4(protected)+8(static)=12
    String job;
    private  double sal;

    //构造器
    public Person(){}
    public Person(String name){}
    private Person(String name,int age){}

    //方法
    public void m1(String name,int age,double sal){

    }

    protected String m2(){
        return null;
    }

    void m3(){

    }

    private void m4(){

    }
}
【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月13日 0

暂无评论

推荐阅读
  TEZNKK3IfmPf   18天前   41   0   0 java
  TEZNKK3IfmPf   2024年05月31日   52   0   0 java
TEZNKK3IfmPf