反射简单应用

反射 Reflection

java属于静态语言,因为反射机制的存在,又可以成为“准动态语言”;

反射允许程序在运行时获取任何类的内部信息,并能直接操作任意对象的内部属性及方法;

正射与反射

正:引入包名 -> 通过new实例化 -> 取得实例化对象;

反:实例化对象 -> getClass() 方法 -> 得到完整的类信息;

反射机制提供的功能

运行时判断任意一个对象所属的类;

​ 构造任何一个类的对象;

​ 判断任何类所具有的成员变量和方法;

​ 获取泛型信息;

​ 调用任何对象的成员变量和方法

​ 处理注解(注解配合反射、绝配);

​ 生成动态代理;

​ 。。。

反射的优缺点

优点:动态、灵活;

缺点:贼慢,比正常new的方式差了几十倍;

反射主要常用API

java.lang.Class : 代表一个类;

java.lang.reflect.Method : 代表类的方法;

java.lang.reflect.Field : 代表类的成员变量;

java.lang.reflect.Constructor : 代表类的构造器;

获取class实例

package com.yuxing.demo;

public class GetClass {
    public static void main(String[] args) throws ClassNotFoundException {
        // 通过getClass获得
        Yuge y1 = new Yuge();
        Class<?> c1 = y1.getClass();
        // 通过forName获得,包名加载
        Class<?> c2 = Class.forName("com.yuxing.demo.Yuge");
        // 通过类直接获得
        Class<Yuge> c3 = Yuge.class;
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());

        // 通过class获得父类的class
        Class<?> superclass = c1.getSuperclass();
        System.out.println(superclass.getName());
    }
}
class Yuge{
}
// 一个类只有一个class
142257191
142257191
142257191
java.lang.Object

什么时候类会发生初始化

类的主动引用

1.虚拟机启动,会先初始化main方法所在的类;

2.new 一个类的对象;

3.调用类的静态成员(除了final常量)和静态方法;

4.使用Java.lang.reflect包的方法对类进行反射调用;

5.当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类;

类的被动引用不会发生类的初始化

1.当访问一个静态域,只有真正声明这个域的类才会被初始化。如:通过子类引用父类的静态变量,不会初始化子类;

public class TestStatic {
    public static void main(String[] args) {
        System.out.println(Son.a);
    }
}
@Data
class Father{
    static int a = 0;
    static{
        System.out.println("父类被加载");
    }
}
@Data
class Son extends Father{
    static{
        System.out.println("子类被加载");
    }
}
父类被加载
0

2.声明数组时,不会初始化

    public static void main(String[] args) {
        Son[] s = new Son[5];
    }
}
@Data
class Son extends Father{
    static{
        System.out.println("子类被加载");
    }
}
没有输出

3.引用常量不会初始化

通过class获得类的信息

Class<?> aClass = Class.forName("com.yuge.redistest.Father");
        aClass.getMethods();
        aClass.getDeclaredMethods();
        aClass.getMethod("aaaa");
		// 参数为方法名
        aClass.getDeclaredMethod("getAaaa");
        aClass.getFields();
		// 获得方法、属性、构造方法等

使用newInstance()获得对象

newInstance()调用的是无参构造,当类没有无参构造方法时,会报错
public class TestStatic {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException {
//        System.out.println(Son.a);
        Class<?> a = Class.forName("com.yuge.redistest.Father");
        Object o = a.newInstance();
        System.out.println(o);
    }
}

@Data
class Father{
    private int b;
    private String a;
//    public Father(){
//
//    }
    public Father( String a,int b){
        this.a = a;
        this.b = b;
    }
}
Exception in thread "main" java.lang.InstantiationException: com.yuge.redistest.Father

newInstance()使用时先获取class的构造方法,传参获取对象
public class TestStatic {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//        System.out.println(Son.a);
        Class<?> a = Class.forName("com.yuge.redistest.Father");
        // 参数为构造方法参数的类型class
        Constructor<?> constructor = a.getConstructor( String.class, int.class);
        Father o1 = (Father)constructor.newInstance("1", 2);
        System.out.println(o1);
    }
}

@Data
class Father{
    private int b;
    private String a;
    public Father( String a,int b){
        this.a = a;
        this.b = b;
    }
}
Father(b=2, a=1)
执行方法、操作属性
public class TestStatic {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
        Class<?> a = Class.forName("com.yuge.redistest.Father");
        Father father = (Father) a.newInstance();
        Method a1 = a.getMethod("getName", String.class);
        // incoke方法,参数为实例对象、和该方法需要的参数
        a1.invoke(father,"aas");
        Field a2 = a.getDeclaredField("a");
        // Father类中的a属性是私有的,无法直接赋值,因此需要将权限检测关闭,才能赋值
        a2.setAccessible(true);
        // set方法,参数为实例对象、和需要设置的值
        a2.set(father,"asfs");
        System.out.println(father);
    }
}

@Data
class Father{
    private int b;
    private String a;
    public void getName(String cc){
        System.out.println(cc);
    }
    public Father(){
    }
    public Father( String a,int b){
        this.a = a;
        this.b = b;
    }
}

反射操作泛型,直接百度,内容内很少

反射操作注解

获取类上的注解,就用class.getAnnotations();

获取方法上的注解就用method.getAnnotation(注解类.class);

获取属性上的注解就用field.getAnnotation(注解类.class);

posted @ 2022-01-04 21:34  窃窃私语QAQ  阅读(23)  评论(0编辑  收藏  举报