反射-备忘录

跳转到总目录

文章目录


反射

程序经过javac.exe(即编译)后,会生成一个或多个字节码文件(.class结尾).接着用java.exe命令对某个字节码文件进行解析,相当于将其加载到内存,此过程就是类的加载.加载到内存中的类,我们称为运行时类,这就是Class的一个实例,会缓存一段时间,期间我们可以进行反射操作.

Class实例的常用获取方式

 public void test1() throws ClassNotFoundException {
        //创建Class的四种方式
        //1.class
        Class<Person> clazz1 = Person.class;
        System.out.println("clazz1 = " + clazz1);
        //2.getClass()
        Class<? extends Person> clazz2 = new Person().getClass();
        System.out.println("clazz2 = " + clazz2);
        //3.Class.forName()(常用)
        Class<?> clazz3 = Class.forName("com.javaboy.train.reflect.Person");
        System.out.println("clazz3 = " + clazz3);
        //4.ClassLoader(了解)
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        Class<?> clazz4 = classLoader.loadClass("com.javaboy.train.reflect.Person");
        System.out.println("clazz4 = " + clazz4);
        System.out.println(clazz1==clazz2);
        System.out.println(clazz3==clazz4);
    }

常用方法

clazz.forName(String classpath) //用clazz表示获取的Class实例对象.
clazz.newInstance() //创建运行时类的对象.
clazz.getDeclaredXxxs(Object …o) //获取运行时类的所有Xxx,不包括父类.
clazz.getXxxs(Object …o) //获取运行时类及父类中声明为public访问权限的Xxx.
以上两个方法去掉s为只获取指定的Xxx.
clazz…getSuperClass() //获取父类
clazz.getGenericSuperclass(): 获取带泛型的父类.
Xxx.setAccessible(): 设置当前Xxx是可访问的.
Field.set()/get(): 设置/获取属性.
method.invoke():调用方法.

实例代码如下:

    public void test() throws Exception{
        //通过反射,创建Person类对象
        Class<Person> clazz = Person.class;
        Constructor<Person> constructor = clazz.getDeclaredConstructor(String.class,int.class);
        Person person = constructor.newInstance("haowu",12);
        System.out.println(person.toString());
        //通过反射,调用对象指定public属性
        Field age = clazz.getDeclaredField("age");
        age.set(person,13);
        System.out.println(person);
        //通过反射,调用对象指定public方法
        Method show = clazz.getDeclaredMethod("show");
        show.invoke(person);
        System.out.println("================================");
        //通过反射调用私有结构
        Constructor<Person> constructor1 = clazz.getDeclaredConstructor(String.class);
        constructor1.setAccessible(true);
        Person person1 = constructor1.newInstance("昊吴");
        System.out.println(person1);
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(person1,"火");
        System.out.println(person1);
        Method showNation = clazz.getDeclaredMethod("showNation",String.class);
        showNation.setAccessible(true);
        showNation.invoke(person1, "中国");
    }

ClassLoader

ClassLoader: 有4种为自定义类加载器,系统类加载器,拓展加载器,引导加载器(负责Java核心库).
clazz.getClassLoader()
new Properties等同于classLoader.getResourceAsStream(“配置文件地址”).

    public void test1(){
        //对于自定义类,使用系统类加载器进行加载
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println("classLoader = " + classLoader);
        //调用系统类加载器的getParent(): 获取扩展类加载器
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println("classLoader1 = " + classLoader1);
        //调用扩展类加载器的getParent(): 无法获取引导加载器
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println("classLoader2 = " + classLoader2);
        // 引导加载器主要负责加载java的核心库类,无法加载自定义类的
        ClassLoader classLoader3 = String.class.getClassLoader();
        System.out.println("classLoader3 = " + classLoader3);
    }

调用运行时类中指定的结构: 属性,方法,构造器

 	@Test
    //调用运行时类中指定的方法(非静态一样的,只不过invoke中的第一个参数可以任意输,不需要为方法的调用者了)
    public void test3() throws Exception {
        Class<?> clazz = Class.forName("com.javaboy.train.reflect.Student");
        //创建运行时类的对象
        Student student = (Student) clazz.newInstance();
        //获取指定的方法(包括非public的) getDeclaredMethod(获取的方法名称,获取方法的形参列表)
        Method method = clazz.getDeclaredMethod("doS", String.class);
        //设置当前属性是可访问的
        method.setAccessible(true);
        //调用方法 invoke(方法调用者,给方法的形参赋值的实参) 返回值为对应方法的返回值
        Object o = method.invoke(student, "方法测试");
        System.out.println(o);
    }

    @Test
    //调用运行时类中指定的属性
    public void test2() throws Exception {
        Class<?> clazz = Class.forName("com.javaboy.train.reflect.Student");
        //创建运行时类的对象
        Student student = (Student) clazz.newInstance();
        //获取指定的属性(包括非public的)
        Field name = clazz.getDeclaredField("name1");
        //设置当前属性是可访问的
        name.setAccessible(true);
        //设置当前属性的值 set(指明设置那个对象的属性,将此属性设置为多少)
        name.set(student,"昊吴");
        //获取当前属性的值 get(指明设置那个对象的属性)
        System.out.println(name.get(student));
    }

    @Test
    //调用运行时类中指定的构造器
    public void test1() throws Exception {
        Class<?> clazz = Class.forName("com.javaboy.train.reflect.Student");
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
        constructor.setAccessible(true);
        Student student = (Student) constructor.newInstance("昊吴", 18);
        System.out.println("student = " + student);
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值