【JavaSE】反射机制-基础概述

JavaSE-反射机制-基础概述

1. 应用场景

常见的如下:

  1. 当获取到一个未知类型但是知道其中的方法名方法参数的类对象时,可以通过反射机制调用这个方法,甚至于获取到这个类的具体信息。

  2. 通过配置文件动态加载类,动态调用类中的方法和属性。

2. 优点

  1. 动态加载:即使用到某个类时,才对这个类进行加载。

3. 缺点

  1. 使用反射的程序是基于解释执行的,影响程序执行速度。

4. Class类解析

了解反射机制,必须先了解Class类,Class实例是在类加载阶段完成的,即根据字节码文件,通过类加载器来实现Class类实例的加载(将字节码的二进制数据和Class类对象放入内存中)。

关于Class类,该类和普通类的主要区别在于

  • 该类是由系统创建。
  • 每一个普通的类都有一个对应的Class类实例,这个实例包括了普通类的字段、方法、构造函数。

Class类中常用的API

方法描述
getName()获取类的完整名称。
getSimpleName()获取类的简单名称,即去掉包名的类名。
getModifiers()获取类的修饰符,比如publicprivate等。
getFields()获取类的公共字段,包括超类的。
getDeclaredFields()获取类声明的所有字段,包括私有的。
getMethods()获取类的公共方法,包括超类的。
getDeclaredMethods()获取类声明的所有方法,包括私有的。
newInstance()创建类的一个新实例(已过时,不推荐使用)。
getConstructor(Class<?>... parameterTypes)获取指定参数类型的构造函数。
getDeclaredConstructor(Class<?>... parameterTypes)获取类声明的构造函数。

5. 获取Class类实例的方式

  1. 类名.class:通常用于传参。
  2. Class.forname(类的全路径名):在已知类的全路径名的前提下,多用于配置文件,读取类的全路径,加载类。
  3. 实例.getClass():通过对象直接获取Class类的实例。
  4. 对象.getClass().getClassLoader().loadClass(类的全路径名):通过类加载器获取Class类实例。
 /**
     * 获取Class实例的六种方式
     */
    @Test
    public void testGetClass() throws Exception{
        //编译期间--->通过调用静态方法forName()获取
        Class<?> cls = Class.forName(PATH_DOG);
        System.out.println(cls);

        //类加载阶段--->通过类名.class获取
        cls = Dog.class;
        System.out.println(cls);


        //运行阶段--->通过对象实例创建Class对象
        Object dog = cls.newInstance();
        System.out.println(dog.toString());
        Class<?> aClass = dog.getClass();
        System.out.println("运行阶段:" + aClass);

        //使用类加载器加载Class类的对象
        Class loadClass = dog.getClass().getClassLoader().loadClass("com.aimin.Dog");


        //基本数据类型
        Class<Integer> integerClass = int.class;
        Class<Character> characterClass = char.class;
        System.out.println(integerClass);
        System.out.println(characterClass);

        Class<Integer> integerClass1 = Integer.TYPE;
        Class<String> stringClass = String.class;
        Class<Character> characterClass1 = Character.TYPE;
        System.out.println(integerClass1);
        System.out.println(stringClass);
        System.out.println(characterClass1);


    }

6. 反射机制是什么

在类加载阶段结束之后,内存中会出现所加载类对应的Class类对象,这个Class类对象包含了所加载类的全部信息,就像一面镜子一样反射了所加载类的全部信息,通过Class类对象就可以操作所加载的全部属性和方法。

7. 反射机制原理图(老韩)

这个图是韩老师课程里面画的图,对类的加载描述地很清晰

Alt

8. 具体应用

  1. 操作类的方法:

    /**
     * 通过反射获取方法对象,并对方法对象进行操作
     */
    public class GetMethodTest {
    
        @Test
        public void getMethod() throws Exception{
            //获取Class类Boss实例
            Class bossCls = Class.forName("com.aimin.Boss");
    
            //获取对象实例
            Object o = bossCls.newInstance();
    
            //获取公有方法对象
            Method hi = bossCls.getMethod("hi", String.class);
    
            //赋值
            hi.invoke(o, "aimin");
    
            //获取私有方法对象
            Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
    
            //开启暴破
            say.setAccessible(true);
    
            //赋值并执行方法获取返回值
            //Object result = say.invoke(o, 1, "What's matter with you ?", 'a');
    
            //由于"say"方法也是静态方法,所以也可以不指定对象
            Object result = say.invoke(null, 1, "What's matter with you ?", 'a');
            System.out.println((String) result);
    
        }
    }
    
    class Monster {
    }
    
    class Boss {//类
        public int age;
        private static String name;
    
        public Boss() {//构造器
        }
    
        public Monster m1() {
            return new Monster();
        }
    
        private static String say(int n, String s, char c) {//静态方法
            return n + " " + s + " " + c;
        }
    
        public void hi(String s) {//普通 public 方法
    
            System.out.println("hi " + s);
        }
    }
    
  2. 操作类的属性:

    /**
     * 通过反射操作对象(一般类型为Object)的属性
     */
    public class OperationFieldTest {
    
        @Test
        public void operationField() throws Exception{
            //获取Class类对象
            Class stuCls = Class.forName("com.aimin.Student");
    
            //获取类实例
            Object stu = stuCls.newInstance();
    
            //通过属性名获取属性对象---公共字段
            Field age = stuCls.getField("age");
    
            //赋值
            age.set(stu, 22);
            System.out.println(age.get(stu));
    
            //通过属性名获取属性对象---私有静态字段
            //由于静态字段与类加载有关,即静态对象是所有类实例共用的,所以在赋值的时候可以不指定对象实例
            Field name = stuCls.getDeclaredField("name");
    
            //开启暴破
            name.setAccessible(true);
    
            //赋值
            //name.set(null, "aimin");
            name.set(stu, "WangBB");
            System.out.println(name.get(null));
    
        }
    
    
    }
    
    
    class Student {//类
        public int age;
        private static String name;
    
        public Student() {//构造器
        }
    
        public String toString() {
            return "Student [age=" + age + ", name=" + name + "]";
        }
    }
    
  3. 获取类实例

    /**
     * 通过反射获取类实例
     */
    public class NewInstanceTest {
    
        @Test
        public void getInstanceByClass() throws Exception{
    
            //获取User类Class类对象
            Class userCls = Class.forName("com.aimin.User");
    
            //通过公有无参构造器创建对象
            Object user01 = userCls.newInstance();
            System.out.println("公有无参构造器" + user01);
    
            //通过公有有参构造器创建对象
            Constructor constructor = userCls.getConstructor(String.class);
    
            Object aimin = constructor.newInstance("aimin");
    
            System.out.println("公有有参构造器" + aimin);
    
            //通过私有构造器创建对象
    
            //1. 获取到私有构造器
            Constructor declaredConstructor = userCls.getDeclaredConstructor(int.class, String.class);
    
            //2. 开启暴破,类四暴力破解,之后才能获取到私有构造器
            declaredConstructor.setAccessible(true);
            Object test = declaredConstructor.newInstance(1, "test");
            System.out.println(test);
    
    
        }
    }
    
    class User { //User 类
        private int age = 10;
        private String name = "韩顺平教育";
    
        public User() {//无参 public
        }
    
        public User(String name) {//public 的有参构造器
            this.name = name;
        }
    
        private User(int age, String name) {//private 有参构造器
            this.age = age;
            this.name = name;
        }
    
        public String toString() {
            return "User [age=" + age + ", name=" + name + "]";
        }
    }
    
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值