Java基础 - 反射篇 - 类加载分析,通过反射获取类的结构API案例

类加载

基本说明

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

  1. 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
  2. 动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性

举例说明(静态加载)

外部ClassLoad_类

import java.util.*;
public class ClassLoad_{
	public static void main(String[] args){
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入key");
		String key = sc.next();
		switch(key) {
			case "1":
				Dog dog = new Dog();//编译时加载类,静态加载
				dog.cry();
				break;
			case "2":
				System.out.println("ok");
				break;
			default:
				System.out.println("do nothing...");
		}
	}
}

dos窗口运行展示

请添加图片描述

举例说明(动态加载)

ClassLoad_类

package com.taotao.reflection.question;

import java.lang.reflect.Method;
import java.util.*;
/**
 * Create By 刘鸿涛
 * 2022/2/26 17:20
 */
public class Test {
    @SuppressWarnings({"all"})
    public static void main(String[] args)throws Exception {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入key");
        String key = sc.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...");
        }
    }
}
//因为new Dog()是静态加载,因此必须编写dog类
//Person类是动态加载,所以,没有编写person类也不会报错,只有当动态加载该类时,才会报错
class Dog {
    public void cry() {
        System.out.println("小狗汪汪叫....");
    }
}

运行展示

请添加图片描述

请添加图片描述

类加载时机

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

类加载过程图

请添加图片描述

请添加图片描述

类加载的五个阶段

加载阶段

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

连接阶段 - 验证

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

准备阶段 - 准备

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

请添加图片描述

案例演示

package com.taotao.reflection.classload_;

/**
 * Create By 刘鸿涛
 * 2022/2/26 18:26
 * 我们说明一个类加载的链接阶段 - 准备
 */
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;
}

连接阶段 - 解析

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

请添加图片描述

数据的内存地址是JVM机来分配的,用户不能控制

Initialization(初始化)

  1. 到初始化阶段:才真正开始执行类中定义的Java程序代码,此阶段是执行clinit()方法的过程。
  2. clinit()方法是由编译器按语句在源文件中出现的顺序,一次自动收集类中的所有“静态变量”的赋值动作和静态代码块中的语句,并进行合并。
package com.taotao.reflection.classload_;

/**
 * Create By 刘鸿涛
 * 2022/2/26 19:10
 * 演示类加载 - 初始化
 */
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);  //B 静态代码块被执行     100
    }
}
class B {
    static {
        System.out.println("B  静态代码块被执行");
        num = 300;
    }
    static int num = 100;
    public B() {
        System.out.println("B() 构造器被执行");
    }
}
  1. 虚拟机会保证一个类clinit()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只有一个线程去执行这个类的clinit()方法,其他线程都需要阻塞等待,直到活动线程执行clinit()方法完毕

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

第一组(java.lang.Class)

  1. getNname:获取全类名
  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[] 形式返回注解信息

演示通过反射获取类的结构信息

package com.taotao.reflection;

import org.junit.Test;

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

/**
 * Create By 刘鸿涛
 * 2022/2/26 23:11
 */
public class ReflectionUtils {
    public static void main(String[] args) {

    }

    //第一组方法API
    @SuppressWarnings({"all"})
    @Test
    public void api_01() throws ClassNotFoundException {
        //得到 Class对象
        Class<?> personCls = Class.forName("com.taotao.reflection.Person");

//        1. getNname:获取全类名
        System.out.println(personCls.getName()); //com.taotao.reflection.Person

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

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

//        4. getDeclaredFields:获取本类中所有属性,本类及父类,包含私有、共有、protected
        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("本类以及父类的方法 = " + 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("本类以及父类的构造器 = " + constructor.getName());
        }       //测试并未得到父类构造器

//        8. getDeclaredConstructors:获取本类中所有构造器,只有本类,没有父类
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors) {
            System.out.println("本类中的所有构造器分别为 = " + constructor.getName());
        }   //测试未得到父类构造器

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

//        10. getSuperClass:以Class形式返回父类信息
        System.out.println("父类的class信息 = " + personCls.getSuperclass());  //class com.taotao.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 A(){
        
    }

    public A(String hobby){

    }
}

interface IA {

}

interface IB {

}

@Deprecated
@SuppressWarnings({"all"})
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(int age){

    }

    //方法
    public void m1() {

    }

    protected void m2() {

    }

    void m3() {

    }

    private void m4() {

    }
}

第二组(java.lang.reflect.Field)

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

说明:默认修饰符是 0,public 是1,private 是 2,protected 是 4, static 是 8 ,final 是16.

如果 是 public static 那么就是 1 + 8 = 9

  1. getType:以Class形式返回类型
  2. getName:返回属性名

演示

package com.taotao.reflection;

import org.junit.Test;

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

/**
 * Create By 刘鸿涛
 * 2022/2/26 23:11
 */
public class ReflectionUtils {
    public static void main(String[] args) {

    }

    @Test
    @SuppressWarnings({"all"})
    public void api_02 () throws ClassNotFoundException {
        //得到 Class对象
        Class<?> personCls = Class.forName("com.taotao.reflection.Person");
        //getDeclareFileds:获取本类中所有属性
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field fields : declaredFields){
            System.out.println("本类中的所有属性分别为 = " + fields.getName() + "  该属性的修饰符值 = " + fields.getModifiers() + "  该属性的类型为 = " + fields.getType());
        }
    }
}

class Person {
    //属性
    public String name;
    protected int age;
    String job;
    private double sal;

    }
}

请添加图片描述

第三组(java.lang.reflect.Method)

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

说明:默认修饰符 是 0 ,public 是 1,private 是 2,protected 是 4, static 是 8 ,final 是16;

  1. getReturnType:以Class形式获取 返回类型
  2. getName:返回方法名
  3. getParameterTypers:以Class[]返回参数类型数组

演示

package com.taotao.reflection;

import org.junit.Test;

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

/**
 * Create By 刘鸿涛
 * 2022/2/26 23:11
 */
public class ReflectionUtils {
    public static void main(String[] args) {

    }
        //getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类的所有方法分别为:" + declaredMethod.getName() + " 该方法的访问修饰符值:" + declaredMethod.getModifiers() +  " 返回类型为:" + declaredMethod.getReturnType());
            //输出当前这个方法的参数情况
            Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.println("该方法的形参类型:" + parameterType);    //class java.lang.String,  int
            }
        }
    }
}

@SuppressWarnings({"all"})
class Person {

    //方法
    public void m1(String a,int b) {

    }

    protected void m2() {

    }

    void m3() {

    }

    private void m4() {

    }
}

第四组(java.lang.reflect.Constructor)

  1. getModifiers:以int形式返回修饰符
  2. getName:返回构造器名(全类名)
  3. getParameterTypes:以Class[]返回参数类型数组

案例

package com.taotao.reflection;

import org.junit.Test;

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

/**
 * Create By 刘鸿涛
 * 2022/2/26 23:11
 */
public class ReflectionUtils {
    public static void main(String[] args) {

    }

    @Test
    @SuppressWarnings({"all"})
    public void api_02 () throws ClassNotFoundException {
        //得到 Class对象
        Class<?> personCls = Class.forName("com.taotao.reflection.Person");


        //getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors) {
            System.out.println("本类中的所有构造器分别为 = " + constructor.getName());

            Class<?>[] paremeterTypes = constructor.getParameterTypes();
            for (Class<?> paremeterType : paremeterTypes) {
                System.out.println("该构造器的形参类型 = " + paremeterType);
            }
            System.out.println();
        }
    }
}

@Deprecated
@SuppressWarnings({"all"})
class Person {
    //属性
    public String name;
    protected int age;
    String job;
    private double sal;

    //构造器
    public Person(){

    }

    public Person(String name,int a){

    }

    public Person(int age){

    }
}

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鬼鬼骑士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值