反射是Java底层的技术,反射主要通过Class,Filed,Method,Constructor这几个类来实现的
    可以通过反射获取任意类的所有信息,还可以创建任意类的对象,还可以调用类中的方法等等
    总的来说的,反射是一个强大的技术,可以让程序的设计更加的灵活
    但是通常情况下很少会用到反射,反射一般在做框架封装的时候,才会大量使用到
    任何一个强大的框架肯定少不了对反射的使用
    比如说我自己封装了一个WEB框架,就是利用反射获取方法上面的注解,进而获取注解中携带的信息

    类是用来描述对象的
    反射可以理解为是用来描述类的
    所有的类都具有相同的特征
    每一个类都有自己的结构 比如 属性 方法 构造方法 都有 权限修饰符 特征 等等

    Class 用来描述类本身 —-> 可以理解为Class对象与硬盘上的.class类文件产生了映射关系
    Package 用来描述类所属的包
    Filed 用来描述类中的属性
    Method 用来描述类中的方法
    Constructor 用来描述类中的构造方法
    Annotation 用来描述类中的注解@Override 注解可以放在 类上面 属性上面 方法上面 构造方法上面 参数前面

    1. 如何获取Class
    有三种方式
    1.1 Class = Class.forName(“包名.类名”);
    1.2 Class = 类名.class; //类名必须存在
    1.3 Class = 对象引用.getClass(); //Object类中的方法
    2. Class中常用的方法
    2.1 int = getModifiers();
    //获取类的修饰符(权限 特征) 得到的结果是所有的对应的值相加
    0 - 默认修饰符 1 - public 2 - private 4 - protected 8 - static
    16 - final 32 - synchronized 64 - volatile 128 - transient
    256 - native 512 - interface 1024 - abstract
    2.2 String = getName();
    //获取类的全名 包名加类名
    String = getSimpleName();
    //获取类名 仅仅就是类的名字
    2.3 Package p = getPackage();
    //获取包
    p.getName();
    //获取包名
    2.4 Class = getSuperClass();
    //获取父类
    2.5 Class[] = getInterfaces();
    //获取当前类的所有父接口

    1. public static void main(String[] args){
    2. try {
    3. //通过包名和类名 可能找不到包 所以会出现异常
    4. // Class clazz = Class.forName("test_reflect.Person");
    5. ArrayList<String> list = new ArrayList<>();
    6. //通过类名.来获取ArrayList父类 因为都知道类名了 所以这里不会出现异常
    7. Class clazz = ArrayList.class;
    8. Class sclazz = clazz.getSuperclass();
    9. while(sclazz!=null){
    10. System.out.println(sclazz.getName());
    11. sclazz = sclazz.getSuperclass();
    12. }
    13. //获取clazz的所有父接口
    14. Class[] classes = clazz.getInterfaces();
    15. for(Class c:classes){
    16. System.out.println(c.getName());
    17. }
    18. //自己有结构 权限修饰符 特征修饰符
    19. int modify = clazz.getModifiers();
    20. //类名字
    21. clazz.getName();//类全名
    22. clazz.getSimpleName();//类名
    23. //获取类所在的包
    24. Package p = clazz.getPackage();
    25. System.out.println(p.getName());
    26. clazz.getSuperclass();
    27. } catch (ClassNotFoundException e) {
    28. e.printStackTrace();
    29. }
    30. }

    2.6 Object obj = calzz.newInstance();
    //相当于调用person类中默认无参数的构造方法创建person对象
    //即 Person p = (Person)clazz.newInstance();
    //如果无参数的构造方法被有参数的覆盖了 这时候抛出异常
    //NOSuchMethodException
    3. Field类
    怎么获取类的属性Field —-> Class类中的方法
    2.7 Filed nameField = getFiled(“属性名”); //需要导包
    //获取类中的 指定属性 公有的 自己类+父类
    Field[] fileds = getFields();
    //获取类中的 全部属性 公有的 自己类+父类
    2.8 Field = getDeclaredField(“属性名”);
    //获取 本类中 指定的 公有的或私有的 属性
    Field[] = getDeclaredFields();
    //获取 本类中 全部的 公有的以及私有的 属性

    1. public static void main(String[] args) throws Exception {
    2. String str = new String("abc");
    3. System.out.println(str);
    4. //反射技术可以获取私有属性 从而去操作私有属性 虽然很不合理
    5. //1.获取String类对应的Class 对象引用.getClass()来获取
    6. Class clazz = str.getClass();
    7. //2.通过clazz获取类中的私有属性value
    8. Field field = clazz.getDeclaredField("value");
    9. //3.直接操作属性是不可以的 找到私有属性不代表能修改 只是给你看见
    10. //要想修改就需要setAccessible 设置私有属性可以被操作
    11. field.setAccessible(true);
    12. //4. 获取value属性里面的值 即内存地址
    13. // private final char[] value = {'a','b','c'};
    14. char[] temp = (char[]) field.get(str);
    15. temp[0] = '你';
    16. temp[1] = '好';
    17. temp[2] = '啊';
    18. System.out.println(str);
    19. //此时value属性里面存的值就发生了改变
    20. }

    Field类中的常用方法
    3.1 int = getModifers();
    //获取属性的修饰符
    3.2 Class fclass = getType();
    //获取 属性的类型 对应的那个类 比如String也有自己对应的Class
    3.3 String fname = getName();
    //获取 属性名
    如何操作属性 往里面 存值 取值?
    3.4 set(对象,值);
    //存值
    3.5 值 = get(对象);
    //取值 因为不确定取值的类型 需造型
    3.6 setAccessable(true);
    //设置访问权限 让私有属性可以被操作
    //若不写这个代码直接操作私有属性 会抛出异常 IllegalAccessException

    1. public static void main(String[] args){
    2. try {
    3. //通过包名和类名 可能找不到包 所以会出现异常
    4. Class clazz = Class.forName("test_reflect.Person");
    5. Person p = (Person)clazz.newInstance();//相当于调用person类中默认无参数的构造方法创建对象
    6. //如果无参数的构造方法被有参数的覆盖了 这时候运行就会出现异常
    7. //通过clazz来获取类中对应的属性
    8. //要知道属性叫什么名字 且是公有的
    9. Field nameField = clazz.getField("name");//需要导包 获取类中的name属性
    10. //获取全部属性 继承过来的也算 且只能获取公有的
    11. //Field[] fileds = clazz.getFields();
    12. //System.out.println(fileds.length);
    13. nameField.getModifiers();//获取 属性的修饰符
    14. Class fclass = nameField.getType();//获取 属性的类型对应的那个类 比如String也有自己对应的Class
    15. String fname = nameField.getName();//获取 属性名
    16. //给属性赋值
    17. nameField.set(p,"小兰");
    18. //取值
    19. String name = (String) nameField.get(p);//因为不确定是什么类型的 所以需要造型
    20. } catch (Exception e) {
    21. e.printStackTrace();
    22. }
    23. }

    4. Method类
    怎么获取类的方法Method —-> Class类中的方法
    2.9 Method m = clazz.getMethod(“方法名”,Class…(参数列表对应的class类型) );
    //获取 指定的 公有的方法(自己类+父类)
    //找不到方法会抛出异常 NOSuchMethodException
    Method[] m = clazz.getMethods();
    //获取 所有的 公有的方法(自己类+父类)
    2.10 Method m = clazz.getDeclaredMethod(“方法名”,Class…(参数列表对应的class类型) );
    //获取 指定的 公有的+私有的 方法(自己类)
    //找不到方法会抛出异常 NOSuchMethodException
    Method[] m = clazz.getDeclaredMethods();
    //获取 所有的 方法(不包括继承的)
    Method类中常用方法
    4.1 int = getModifers();
    //获取方法的修饰符
    4.2 Class fclass = getReturnType();
    //获取 方法的 返回值数据类型所对应的类
    4.3 String fname = getName();
    //获取 方法名
    4.4 Class[] = getParameterTypes();
    //获取 方法的 参数列表类型所对应的类
    4.5 Class[] = getExceptionTypes();
    //获取 方法的 抛出异常类型所对应的类
    如何操作方法 让其执行?
    4.6 Object result = (Object) invoke(方法所属对象,执行方法需要传递的参数…);
    //动态参数列表 传多少个参数都行 但是方法需要多少个参数就传几个 不然会抛出异常
    4.7 setAccessable(true);
    //设置访问权限 让私有方法可以被执行
    //若不写这行代码直接执行私有方法 会抛出异常 IllegalAccessException

    1. public class Person{
    2. private String name;
    3. public int age;
    4. public String toString(){
    5. return this.name+"-"+this.age;
    6. }
    7. public void eat(){
    8. System.out.println("我是Person类无参数的方法");
    9. }
    10. public String eat(String s){
    11. System.out.println("我是Person类带String参数的方法");
    12. return s;
    13. }
    14. private void privateMethod(){
    15. System.out.println("我是私有的方法");
    16. }
    17. }
    18. public static void main(String[] args) {
    19. try {
    20. //获取Person对应的Class
    21. Class clazz = Person.class;
    22. Person p = (Person)clazz.newInstance();
    23. //通过方法名字定位方法 再通过方法参数类型对应的Class来找寻相对应的方法 如String类型有自己对应的Class
    24. Method m = clazz.getMethod("eat",String.class);//方法找不到会抛出异常
    25. String result = (String) m.invoke(p,"测试1");
    26. System.out.println(result);
    27. //获取私有的方法
    28. Method m1 = clazz.getDeclaredMethod("privateMethod");
    29. //访问私有方法的权限
    30. m1.setAccessible(true);
    31. //执行私有方法
    32. m1.invoke(p);
    33. } catch (Exception e) {
    34. e.printStackTrace();
    35. }
    36. }

    5. Constructor类
    怎么获取类的构造方法Costructor —-> Class类中的方法
    2.11 Costructor c = clazz.getConstructor ( Class…(参数列表对应的class类型) );
    //获取 指定 构造方法
    Costructor[] cons = clazz.getConstructors ( Class…(参数列表对应的class类型) );
    //获取 全部 构造方法
    2.12 Costructor c = clazz.getDeclaredConstructor ( Class…(参数列表对应的class类型) );
    //获取 指定的私有或公有的 构造方法
    Costructor[] cons = clazz.getDeclaredConstructors ( Class…(参数列表对应的class类型) );
    //获取 全部的私有+公有的 构造方法
    Costructor类中常用方法
    5.1 int = getModifers();
    //获取 构造方法的修饰符
    5.2 String fname = getName();
    //获取 方法名
    5.3 Class[] = getParameterTypes();
    //获取 构造方法的 参数列表类型所对应的类
    5.4 Class[] = getExceptionTypes();
    //获取 构造方法的 抛出异常类型所对应的类
    如何操作构造方法 创建对象?
    5.5 Object result = (Object)newInstance ( 执行构造方法需要传递的参数… );
    //动态参数列表 传多少个参数都行 但是 构造方法需要多少个参数就传几个 不然会抛出异常
    5.6 setAccessable(true);
    //设置访问权限 让私有构造方法可以被执行
    //若不写这行代码直接执行私有构造方法 会抛出异常 IllegalAccessException