只有血的教训,才会有记性

Java反射

我理解的反射机制

Java的反射机制,就是Java在运行的时,对任意的类,都可以获取它的全部信息,包括属性,方法等等。这种动态获取的方法就是反射,
比如说现在有一个学生类,还有学生类的.class文件,那么只要知道它的类名,就可以获取它的所有属性,方法。
再举个简单的例子,现在我们有Student.java类,我只有它的 .calss 文件而且我还知道它的类名是Student,那么我现在怎么获取它的构造方法和一些属性,那么这个时候就要用大反射了。

代码实现

那么,现在就考虑一个问题,如何根据类的类名,来获取类的完整信息呢?
1,依靠类名获取class对象
2,通过class对象的函数接口,获取信息

package com.westos.day20;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //根据类名获取class对象
        Class<?> aClass = Class.forName("com.westos.day20.Student");
        //新建对象newInstance()会调用不带参数的构造函数
        Object obj = aClass.newInstance();
        System.out.println("aClass"+aClass);
    }
}
class Student{
    public Student() {
        System.out.println("学生类");
    }
}

运行结果
学生类
aClassclass com.westos.day20.Student

那么再了解了基本原理的时候,再稍微进一步的理解一下吧

1 获取Class对象的方法
方法1:Class.forName(“类名字符串”) (注意:类名字符串必须是全称,包名+类名)
方法2:类名.class
方法3:实例对象.getClass()
方法4:“类名字符串”.getClass()

package com.westos.day20;

public class Test2 {
    public static void main(String[] args) {
        //方法一
        try {
            //方法一
            Class<?> aClass = Class.forName("com.westos.day20.Student");
            //方法二
            Class<Student> aClass1 = Student.class;
            //方法三
            Student student = new Student();
            Class<? extends Student> aClass2 = student.getClass();
            //方法四
            Class<? extends String> aClass3 = "com.westos.day20.Student".getClass();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
class Student{
    public Student() {
        System.out.println("学生类");
    }
}

再然后就是一些获取方法和属性的函数,我总结了一下
一般方法名字最后以s结尾的就是获取所有返回一个列表或者集合。
一般含有Declared字符的方法可以获取所有的方法,包括私有公有的都可以获取,但是不获取继承的方法,属性。没有这个字符的一般只可以获取公共的方法和属性,还可以获取到继承的方法,属性。

1)获取方法信息

类对象.getMethods(); // 获取所有公共方法(public),包括继承的
类对象.getDeclaredMethods(); // 获取本类的所有方法(public, private, protected, 不加)

类对象.getMethod(方法名, 参数类型); // 找公共方法, 包括继承的
类对象.getDeclaredMethod(方法名, 参数类型); // 找本类的,不包括继承的

2)获取属性信息(了解)

类对象.getFields(); // 获取所有公共属性(包括继承的)
类对象.getDeclaredFields(); // 获取本类所有属性(private public protected 不加)(不包括继承的)
类对象.getField(“属性名”);
类对象.getDeclaredField(“属性名”);

3) 获取构造方法(了解)

类对象.getConstructors(); // 获取所有公共的构造方法
类对象.getDeclaredConstructors(); // 获取本类所有构造方法(private public protected 不加)
类对象.getConstructor(int.class); // 获取int参数类型的构造
类对象.getConstructor(); // 获得无参构造

5) 反射调用方法

正常调用方式: 对象.方法名(参数)
反射调用方式: 方法.invoke(对象, 参数);
缺点:调用复杂,效率低
优点:可以调用私有方法,突破正常方法的限制, 经常用在开源框架中
举一个宝藏的例子,对反射的所有知识进行总结:
<mark>例子</mark>
问:有一个关于宝藏的.class文件,其中有很多的方法,只有一个方法是宝藏信息,而且此方法进行了(@Resource)标记。只有三次机会如何找到宝藏(也就是调用到方法)??
已知条件(.class 文件和宝藏类名)
<mark>分析</mark>
首先将.class加载,得到.class对象,然后得到.class实例对象,然后反射找到带有标记的方法并且调用

<mark>代码</mark>

package com.westos.day20;


import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestThrues {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
        //类加载器
        ClassLoader classLoader = new ClassLoader(){
            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                try {
                    //将类以二进制的形式写入
                    FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Administrator\\IdeaProjects\\day20-2day1\\src\\com\\westos\\Treasure.class");
                    byte[] bytes = new byte[1024 * 8];
                    int len = fileInputStream.read(bytes);
                    //将二进制的加载成类Class
                    return defineClass(name,bytes,0,len);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        };
        Class clazz = classLoader.loadClass("com.westos.Treasure");
        //获得私有的构造方法
        Constructor constructor = clazz.getDeclaredConstructor();
        //将私有的构造方法设置成可以访问的,也就是公共的了
        constructor.setAccessible(true);
        //得到class的实例对象
        Object o =  constructor.newInstance();
        //得到所有方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            //找到带有标记的方法
            Resource resource = method.getAnnotation(Resource.class);
            if (resource!=null){
                method.invoke(o);
            }
        }
    }
}

运行结果:

就把这个宝藏类也贴出来,有兴趣的童鞋可以复制过去自己玩一玩,巩固一下反射的知识点。
宝藏类

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.westos;

import javax.annotation.Resource;

public class Treasure {
    static int count = 3;

    private Treasure() {
        System.out.println("忽然有光!");
    }

    public void m2ab8ff1746a34907ab94ae970b4757f4() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,老鼠四处乱跑!");
        }
    }

    public void m99e25de9cbcf47fc88fbc461e36761b9() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,老鼠四处乱跑!");
        }
    }

    public void m8d01e914283b42b488f5aefbe6d73ffd() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,黄鼠狼蹿了出来!");
        }
    }

    public void mc21085e018bc48f586b0365a2778263d() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,只有树根,卡住了你的铁锹!");
        }
    }

    public void m2d1ee920dc514c56999f667a6afe92be() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,老鼠四处乱跑!");
        }
    }

    public void m1f76b49673c340a98554da282757f2c9() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,只有坚硬的岩石,震得双手隐隐作痛!");
        }
    }

    public void m582e0cc1e82e4e4ca1e982957dd5290d() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,一只蛇蹿了出来,吓了你一跳!");
        }
    }

    public void mf43f36bd907042379eeb442176865594() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,只有树根,卡住了你的铁锹!");
        }
    }

    public void mf502f3628e364c1e9b735dc69fa58822() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,铲倒了自己脚上,鲜血直流!");
        }
    }

    public void mebb2190ffc0c4211a5d32409e82af5d6() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,只有坚硬的岩石,震得双手隐隐作痛!");
        }
    }

    public void m58bc2e8a640640c2b29559a2c377ab13() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,只有泥巴,你不禁叹息!");
        }
    }

    public void m87ac2071ac0c4bb5a7af45297d1f1de1() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,老鼠四处乱跑!");
        }
    }

    public void ma01ec74c7f004c58b7e7d8d218f237f6() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,铲倒了自己脚上,鲜血直流!");
        }
    }

    public void me247e3d53e724001a4e828add5698d3c() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,只有树根,卡住了你的铁锹!");
        }
    }

    public void m1841c14298734808a7b3c41a00f6d2a0() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,铲倒了自己脚上,鲜血直流!");
        }
    }

    @Resource
    public void mbea0e4d50f584e0cb01c836bc14369f1() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,宝箱出现!里面有一个大大的红包,拆开一看【好好学习,天天向上】");
        }
    }

    public void m6edcaa9a86474bdab5ca3dbffc970eb3() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,老鼠四处乱跑!");
        }
    }

    public void m56b13ed30fb8444b865d6bbe7fddd75e() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,老鼠四处乱跑!");
        }
    }

    public void m14407f75513544e9a7c2d09a438143ef() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,只有树根,卡住了你的铁锹!");
        }
    }

    public void m69690f6928c449f2b647bb0cf79b39b4() {
        if (--count < 0) {
            throw new RuntimeException("体力耗尽,不能再挖了!");
        } else {
            System.out.println("你一锹挖下去,只有树根,卡住了你的铁锹!");
        }
    }
}