Java反射(二)

  获取 Class 类对象的六种方式 
//1. Class.forName
        String classfullpath = "com.edu.car";
        Class cls = Class.forName(classfullpath);
        System.out.println(cls);

Constructor constructor2 = cls.getConstructor(String.class, int.class);
//2.类名.class,应用场景,参数传递
        Class cls2 = Car.class;
        System.out.println(cls2);

//3.对象.getClass(),应用场景,有对象实例,运行类型
        Car car = new Car();
        Class cls3 = car.getClass();

//4. 通过类加载器【4 种】来获取到类的 Class 对象
        //(1)先得到类加载器 car
        ClassLoader classLoader = car.getClass().getClassLoader();
        //(2)通过类加载器得到 Class 对象
        Class cls4 = classLoader.loadClass(classfullpath);
        System.out.println(cls4);

对于类加载器classloader,还可以用来给加载类所在目录下的资源文件
https://www.cnblogs.com/macwhirr/p/8116583.html

不同的阶段有不同的获取Class对象方法

哪些类型有Class对象
1.外部类,成员内部类,静态内部类,局部内部类,匿名内部类
2.interface:接口
3.数组
4.enum:枚举
5.annotation:注解
6.基本数据类型
7.void
类的动态加载和静态加载
new创建对象的方式称作为 静态加载 ,编译时加载相关的类,如果不存在该类,编译时会报错
使用Class.forName("XXX")称作为 动态加载 ,运行时加载类,如果不存在该类,在编译时不会检查,直到运行到要加载该类的时候,才会报错,如果运行时,不使用该类仍然不会报错
类加载时机:
类加载流程图:
类加载的五个部分:
一、加载阶段
由类加载器完成,将字节码从不同的数据源(可能是class文件,也可能是jar包或者网络)转化为二进制字节流加载到内存【方法区】中
二、连接阶段--验证:
为了确保class文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全
包括:文件格式验证(class文件是否cafebabe开头),元数据验证,字节码验证和符号引用验证
可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间
二、连接阶段--准备
JVM会在该阶段对 静态变量,分配内存并默认初始化(对应数据类型的默认初始值,如0,0L,null,false等)这些变量所使用的内存都将在方法区中进行分配
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;
}

三、连接阶段--解析
虚拟机将常量池内的符号引用替换为直接引用的过程
四、initialization(初始化)
1.到该阶段才是真正开始执行类中定义的Java程序,是执行<client>()方法的过程
2.<client>()方法是由编译器按语句在原文中出现的顺序,依次自动收集类中的所有 静态变量的赋值动作和静态代码块中的代码,并进行合并
3.虚拟机会保证一个类的<client>()方法在多线程环境下被正确的加锁,同步。如果多个线程同时去初始化一个类,那么只会有一个线程去执行该类的<client>()方法,其他线程需要阻塞等待,直到活动进行执行<client>()方法完毕
通过反射(Class对象)获得类的结构信息
第一组:Java.lang.Class
//第一组方法API
    @Test
    public void api_01() throws ClassNotFoundException, NoSuchMethodException {

        //得到Class对象
        Class<?> personCls = Class.forName("com.hspedu.reflection.Person");
        //getName:获取全类名
        System.out.println(personCls.getName());//com.hspedu.reflection.Person
        //getSimpleName:获取简单类名
        System.out.println(personCls.getSimpleName());//Person
        //getFields:获取所有public修饰的属性,包含本类以及父类的
        Field[] fields = personCls.getFields();
        for (Field field : fields) {//增强for
            System.out.println("本类以及父类的属性=" + field.getName());
        }
        //getDeclaredFields:获取本类中所有属性
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本类中所有属性=" + declaredField.getName());
        }
        //getMethods:获取所有public修饰的方法,包含本类以及父类的
        Method[] methods = personCls.getMethods();
        for (Method method : methods) {
            System.out.println("本类以及父类的方法=" + method.getName());
        }
        //getDeclaredMethods:获取本类中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本类中所有方法=" + declaredMethod.getName());
        }
        //getConstructors: 获取所有public修饰的构造器,包含本类
        Constructor<?>[] constructors = personCls.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("本类的构造器=" + constructor.getName());
        }
        //getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名
        }
        //getPackage:以Package形式返回 包信息
        System.out.println(personCls.getPackage());//com.hspedu.reflection
        //getSuperClass:以Class形式返回父类信息
        Class<?> superclass = personCls.getSuperclass();
        System.out.println("父类的class对象=" + superclass);//
        //getInterfaces:以Class[]形式返回接口信息
        Class<?>[] interfaces = personCls.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println("接口信息=" + anInterface);
        }
        //getAnnotations:以Annotation[] 形式返回注解信息
        Annotation[] annotations = personCls.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("注解信息=" + annotation);//注解
        }


    }

第二组:Java.lang.reflect.Field类

getType返回属性所对应类的Class对象

第三组:Java.lang.reflect.Method类

第四组:Java.lang.reflect.Constructor类

@Test
    public void api_02() throws ClassNotFoundException, NoSuchMethodException {
        //得到Class对象
        Class<?> personCls = Class.forName("com.hspedu.reflection.Person");
        //getDeclaredFields:获取本类中所有属性
        //规定 说明: 默认修饰符 是0 , public  是1 ,private 是 2 ,protected 是 4 , static 是 8 ,final 是 16
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本类中所有属性=" + declaredField.getName()
                    + " 该属性的修饰符值=" + declaredField.getModifiers()
                    + " 该属性的类型=" + declaredField.getType());
        }

        //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);
            }
        }

        //getDeclaredConstructors:获取本类中所有构造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("====================");
            System.out.println("本类中所有构造器=" + declaredConstructor.getName());//这里老师只是输出名

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



        }

    }

通过反射构建对象(私有构造【爆破】和共有构造)的方法:
1.调用无参构造:

//调用类中的无参构造器,必须是public修饰
Class cls = Class.forName(classpath);
//(2) 通过cls 得到你加载的类 com.edu.Cat 的对象实例
Object o = cls.newInstance();

2.通过Constructor调用有参构造

//使用getConstructor获取构造器,构造函数不能是private
Constructor constructor2 = cls.getConstructor(String.class, int.class);
Object o1 = constructor2.newInstance("a", 1);
//要获得private的构造器对象,使用getDeclaredConstructor方法
Constructor declaredConstructor = cls.getDeclaredConstructor(String.class, int.class);
//但是仍然不可以new对象,因为构造器是私有的
Object a = declaredConstructor.newInstance("a", 1);


//在获取了构造器对象declaredConstructor 之后,需要关闭安全访问检查,在newInstance
declaredConstructor.setAccessible(true);
Object a = declaredConstructor.newInstance("a", 1);

 通过反射获取属性对象(私有属性【爆破】和共有属性)的方法:



//getField不能得到私有的属性对象,可以使用getDeclaredField(属性名)
Object o = stuClass.newInstance();//o 的运行类型就是 Student


Class<?> stuClass = Class.forName("com.hspedu.reflection.Student");
//使用反射操作私有属性 name 属性
Field name = stuClass.getDeclaredField("name");
//对 name 进行暴破, 可以操作 private 属性
name.setAccessible(true);
name.set(o, "xxx");
//如果name还是static修饰,可以将o写成null

 通过反射获取方法对象(私有方法【爆破】和共有方法)的方法:

//通过方法名和参数列表来获取method对象,通过getDeclaredMethod方法获取私有方法对象

Class<?> bossCls = Class.forName("com.hspedu.reflection.Boss");
Object o = bossCls.newInstance();
//调用 public 的 hi 方法
//Method hi = bossCls.getMethod("hi", String.class);//OK
//调用私有private的hi方法
Method hi = bossCls.getDeclaredMethod("hi", String.class);//OK
hi.invoke(o, "教育~");
//同样如果hi方法是static修饰,你仍可以将invode方法中o写成null

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Meikesibondwell

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

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

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

打赏作者

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

抵扣说明:

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

余额充值