反射

反射

1.概念

反射:程序在运行时可以动态获取指定类的信息

利用反射机制,开发者可以在 JVM 运行期间做的事:

  1. 判断任意一个对象所属类
  2. 判断任意一个类中所有成员变量及方法
  3. 任意调用一个对象的方法
  4. 构造任意一个类的对象

Class类是反射的基础,我们要在程序运行期间获取一个类的相关信息,就需要Class类

2.获取Class对象

  1. 类名.class
Class<Person> clazz = Person.class;

​ 2.对象.getClass()

 Person person = new Person();
 Class clazz = person.getClass();

​ 3.``Class.forName(类的全路径名)`

Class clazz = Class.forName("com.study.test3.Person");

3.通过反射创建对象

通过反射创建对象的步骤:

  1. 获取构造参数
  2. 创建对象
(1)获取构造参数
public class Demo1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        //获取Class对象
        Class<User> clazz = (Class<User>)Class.forName("com.dream.reflect.User");

        //获取无参构造
        Constructor<User> constructor1 = clazz.getConstructor();

        //获取带String和int类型参数的无参构造
        Constructor<User> constructor2 = clazz.getConstructor(String.class, int.class);

        //获取所有的构造方法(不包括私有的)
        Constructor<?>[] constructorAll = clazz.getConstructors();

/*
方法名不带Declared 只能获取public修饰的方法
方法名带Declared 能获取所有权限修饰符修饰的方法
 */
       
        //获取无参构造
        Constructor<User> constructor3 = clazz.getDeclaredConstructor();

        //获取带String类型参数的私有无参构造
        Constructor<User> constructor4 = clazz.getDeclaredConstructor(String.class);

        //获取所有的构造方法(包括私有的)
        Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();

    }
(2)创建对象
public class Dmeo2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<User> clazz = (Class<User>)Class.forName("com.dream.reflect.User");

        Constructor<User> constructor = clazz.getConstructor(String.class, int.class);
        //创建类的对象
        User user = constructor.newInstance("牟帆", 24);
        System.out.println(user);
         /*
        获取私有的构造方法并访问
        注意:
        获取:必须使用带Declared的方法
        访问:必须先开启访问权限
         */
        Constructor<User> declaredConstructor = clazz.getDeclaredConstructor(String.class);
        //开启访问权限
        declaredConstructor.setAccessible(true);
        User user1 = declaredConstructor.newInstance("冰儿");
        System.out.println(user1);
    }
}

4.通过反射获取类的属性

Filed的获取

getField(String name):获取指定名称的属性对象

getFields():获取所有的属性对象

getDeclaredField(String name):获取任意权限的指定名称的属性对象

getDeclaredFields():获取任意权限的所有的属性对象

Filed的操作

set(Object obj, Object value):将指定的值赋值给指定对象的指定属性

​ ``set(java对象, 属性的值)`

get(Object obj):获取指定对象的指定属性的值

get(java对象)

/*
    获取属性   操作属性
 */
public class Demo4 {
    public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1.获取Class对象
        Class<Admin> clazz = Admin.class;
        //2.获取Admin类所有的public修饰的属性包括继承过来的
        Field[] fields1 = clazz.getFields();
        //3.获取Admin类所有的属性包括private修饰的
        Field[] fields2 = clazz.getDeclaredFields();

        System.out.println(Arrays.toString(fields1));
        System.out.println(Arrays.toString(fields2));


        //获取gender属性
        Field genderField = clazz.getDeclaredField("gender");
        //获取bbb属性
        Field bbbField = clazz.getField("bbb");

        System.out.println("-------------操作属性:取值、赋值---------------------------------");
        //给gender属性赋值
        /*
        属性对象.set(java对象, 属性的值)
         */
        //要操作private修饰的属性必须先开启权限
        genderField.setAccessible(true);

        Constructor<Admin> constructor = clazz.getConstructor();
        Admin admin = constructor.newInstance();
        genderField.set(admin, '男');

        //取出gender属性的值
        /*
        属性对象.get方法(java对象)
         */
        System.out.println(genderField.get(admin));//jay
    }
}

5.通过反射获取类德方法

Method的获取

getMethod(String 方法名,形参列表): 获取指定方法(不能获取私有方法)

getDeclaredMethod(String 方法名,形参列表): 获取指定方法(可以获取私有方法)

Method的操作

方法对象.invoke(Java对象,形参列表): invoke方法的返回值,就是指定的方法的返回值。
如果指定的方法没有返回值,则invoke方法返回null

/*
获取方法  操作方法
 */
public class Demo5 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<Admin> clazz = Admin.class;

        /*
        获取所有的公共方法包括继承的
         */
        Method[] methods1 = clazz.getMethods();
        /*
        获取当前类的所有权限的方法
         */
        Method[] methods2 = clazz.getDeclaredMethods();

        System.out.println(Arrays.toString(methods1));
        System.out.println(Arrays.toString(methods2));

        /*
            获取指定方法
            类对象.getMethod(String 方法名,形参列表)
            类对象.getDeclaredMethod(String 方法名,形参列表)
         */
        //获取Admin类的test方法
        Method method = clazz.getDeclaredMethod("test", String.class);
        System.out.println("------------------执行方法-------------------");
        /*
        执行方法
        方法对象.invoke(Java对象,形参列表)
        invoke方法的返回值,就是指定的方法的返回值
        如果指定的方法没有返回值,则invoke方法返回null
         */
        method.setAccessible(true);

        Constructor<Admin> constructor = clazz.getConstructor();
        Admin admin = constructor.newInstance();
        /*
        执行指定方法,并接收该方法的返回值
         */
        Object result = method.invoke(admin, "哈哈哈");
        System.out.println(result);//输出返回值
    }
}

6.通过反射获取注解

例1

1.自定义注解
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
    String value(); // 这是注解的一个属性字段,也就是在使用注解时填写在括号里的参数
}
2.创建 TestController 类,然后在 TestController 类中使用 @MyRequestMapping 注解,代码如下:
@MyRequestMapping("/test")
public class TestController {
    public void test() {
        System.out.println("进入Test方法");
    }
}
3.测试类代码
public class Test {
    public static void main(String[] args) {
        Class<?> c = TestController.class;
        //获取该类中@MyRequestMapping 注解对象
        MyRequestMapping baseRequestMapping = c.getAnnotation(MyRequestMapping.class);
        System.out.println(baseRequestMapping.value()); // 输出value的值
        
        //获取该类中所有注解对象
        Annotation[] atnsArray = c.getAnnotations();
        for (Annotation an : atnsArray) {
            System.out.println(an);
        }
    }
}

Annotation[] getAnnotations():获取所有注解(不包括私有)

Annotation[] getDeclaredAnnotations():获取所有注解(包括私有)

<A extends Annotation> A getAnnotation(Class<A> annotationClass):获取指定注解

7.注意

如果方法名不带Declared,只能获取公共的属性/方法

同时还有获取继承过来的属性/方法

如果方法名Declarred,能获取任意权限的属性/方法

但是不能获取继承过来的属性/方法

8.反射的优缺点

缺点:

  1. 反射代码的可读性和可维护性比较低
  2. 反射代码执行的性能低
  3. 反射破坏了封装性

优点:

  1. 可以在运行期间获取类的信息、并操作一个类的方法,提高程序的灵活性和扩展性
posted @ 2022-06-30 00:13  snail05  阅读(30)  评论(0)    收藏  举报