Java 反射机制

一:反射的理解

    理解:Java 反射是可以让我们在运行时获取类的方法、属性、父类、接口等类的内部信息的机制。也就是说,反射本质上是一个“反着来”的过程。我们通过new创建一个类的实例时,实际上是由Java虚拟机根据这个类的Class对象在运行时构建出来的,而反射是通过一个类的Class对象来获取它的定义信息,从而我们可以访问到它的属性、方法,知道这个类的父类、实现了哪些接口等信息。

    对象——>类——>调用里面的成员

    反射的作用: 假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。


二:主要功能,常用方法
功能:
     * 在运行时判断任意一个对象所属的类;
    * 在运行时构造任意一个类的对象;
    * 在运行时判断任意一个类所具有的成员变量和方法;
    * 在运行时调用任意一个对象的方法;
    * 生成动态代理。

方法:
* Class类
*         getFields()
*         getDeclaredFields()
*         getMethods()
*         getDeclaredMethods()
*         getDeclaredConstructors()
*
*         getName()
*         getSimpleName()
特点:
    1.Class本身也是一个类
    2.Class 对象只能由系统建立对象
    3.一个类在 JVM 中只会有一个Class实例
    4.一个Class对象对应的是一个加载到JVM中的一个.class文件
    5.每个类的实例都会记得自己是由哪个 Class 实例所生成
    6.通过Class可以完整地得到一个类中的完整结构

* Field类
*         getModifiers():以int形式返回修饰符
*         getType():获取Class类型的属性类型
*         getName():获取属性名
*
* Method类
*         getModifiers():以int形式返回修饰符
*         getReturnType():获取Class类型的方法返回类型
*         getName():获取方法名
*         getParameterTypes():获取参数数组,类型Class[]
*
*
* Constructor类
*         getModifiers():以int形式返回修饰符
*         getName():获取构造器的全类名
*         getParameterTypes():获取参数数组,类型Class[]

* Class:
*         getField(String name):根据属性名获取属性对象(只能获取public修饰的,包含父类继承来的)
*         getDeclaredField(String name):根据属性名获取属性对象(可以获取本类定义的所有的,不问修饰符)
*         getMethod(String name,Class...class):根据方法名和参数列表获取方法对象(只能获取public修饰的,包含父类继承来的)
*         getDeclaredMethod(String name,Class...class):根据方法名和参数列表获取方法对象(可以获取本类定义的所有的,不问修饰符)
*
*
* Field:
*
*         set(对象,新值)
*         get(对象)
*         setAccessible(true)
*
*         注意:如果是静态属性,对象更改为null即可
*
* Method:
*         invoke(对象,Object...obj)
*         setAccessible(true)


getDeclaredFields 和 getFields 的区别:
getDeclaredFields()获得某个类的所有申明的字段,即包括public、private和proteced,但是不包括父类的申明字段。
getFields()获得某个类的所有的公共(public)的字段,包括父类。


Annotation
三个基本的Annotation:
    –@Override:限定重写父类方法,该注释只能用于方法
    –@Deprecated:用于表示某个程序元素(类,方法等)已过时
    –@SuppressWarnings:抑制编译器警告.





三:反射的使用

    创建 Class的三种方法
1. /**
2.  * 获取Class对象的三种方式
3.  * 1 Object ——> getClass();
4.  * 2 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
5.  * 3 通过Class类的静态方法:forName(String  className)(常用)
6.  *
7.  */  
8. public class Fanshe {  
9.     public static void main(String[] args) {  
10.         //第一种方式获取Class对象    
11.         Student stu1 = new Student();//这一new 产生一个Student对象,一个Class对象。  
12.         Class stuClass = stu1.getClass();//获取Class对象  
13.         System.out.println(stuClass.getName());  
14.           
15.         //第二种方式获取Class对象  
16.         Class stuClass2 = Student.class;  
17.         System.out.println(stuClass == stuClass2);//判断第一种方式获取的Class对象和第二种方式获取的是否是同一个  
18.           
19.         //第三种方式获取Class对象  
20.         try {  
21.             Class stuClass3 = Class.forName("fanshe.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名  
22.             System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象  
23.         } catch (ClassNotFoundException e) {  
24.             e.printStackTrace();  
25.         }  
26.           
27.     }  
28. }

    注意:在运行期间,一个类,只有一个Class对象产生。
    三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,一个字符串可以传入也可写在配置文件中等多种方法。



通过反射获取类中的 三大主要成员:属性、方法、构造器

     /**
      * 功能:通过反射打印对应类中的所有属性
      *
      * @param c
      *            Class类的对象
      */
     public static void printFields(Class c) {
         // Field[] fields =
         // c.getFields();//只能获取所有public修饰的属性,包含从父类继承来和自身定义,不限于直接父类
         Field[] fields = c.getDeclaredFields();// 可以获取本类中定义的所有属性,不问修饰符
         for (Field field : fields) {
              // ①修饰符
              int mod = field.getModifiers();
              String modifier = Modifier.toString(mod);
              // ②属性类型
              String typeName = field.getType().getSimpleName();
              // ③属性名
              String name = field.getName();
              System.out.println(modifier + "\t" + typeName + "\t" + name);
         }
     }
     /**
      * 功能:通过反射打印所有 的构造器
      *
      * @param c
      */
     public static void printConstructors(Class c) {
         Constructor[] constructors = c.getDeclaredConstructors();
         for (Constructor constructor : constructors) {
              // ①修饰符
              String modifier = Modifier.toString(constructor.getModifiers());
              // ②方法名
              // String name = constructor.getName();//全类名
              String name = c.getSimpleName();// 简单类名&构造器名
              // ③参数列表
              Class[] parameterTypes = constructor.getParameterTypes();
              StringBuilder builder = new StringBuilder("(");
              for (int i = 0; i < parameterTypes.length; i++) {
                  String simpleName = parameterTypes[i].getSimpleName();
                  builder.append(simpleName);
                  if (i == parameterTypes.length - 1)
                       continue;
                  builder.append(',');
              }
              builder.append(")");
              System.out.println(modifier + "\t" + name + builder);
         }
     }
     /**
      * 功能:通过反射打印所有 的方法
      *
      * @param c
      */
     public static void printMethods(Class c) {
         // 步骤1:获取所有方法
         // Method[] methods =
         // c.getMethods();//只能获取所有public修饰的方法,包含从父类继承来的和自身定义的,不限于直接父类
         Method[] methods = c.getDeclaredMethods();// 可以获取本类中定义的所有方法,不问修饰符
         // 步骤2:遍历每个方法,打印每个方法签名的四要素
         for (Method method : methods) {
              // public void setAge(int,String)
              // ①修饰符
              String modifier = Modifier.toString(method.getModifiers());
              // ②返回类型
              String returnTypeName = method.getReturnType().getSimpleName();
              // ③方法名
              String name = method.getName();
              // ④参数列表
              Class[] parameterTypes = method.getParameterTypes();
              StringBuilder builder = new StringBuilder("(");
              for (int i = 0; i < parameterTypes.length; i++) {
                  String simpleName = parameterTypes[i].getSimpleName();
                  builder.append(simpleName);
                  if (i == parameterTypes.length - 1)
                       continue;
                  builder.append(',');
              }
              builder.append(")");
              System.out.println(modifier + "\t" + returnTypeName + "\t" + name
                       + builder);
         }
     }



    通过反射访问属性和方法

     // 访问方法
     /*
      * public void setAge(int age) { protected int getAge() {
      */
     @Test
     public void test2() throws Exception {
         // 1.根据方法名和参数列表获取方法对象
         // c.getMethod(name, parameterTypes) //只能获取public修饰的方法,包含从父类继承来的,不限于直接父类
         Method method = c.getDeclaredMethod("getAge");// 获取本类中定义的所有方法,不问修饰符
         method.setAccessible(true);
         // 2.创建对象
         // Object obj = c.newInstance();
         // 3.调用方法
         Object returnValue = method.invoke(null);
         System.out.println("返回值:" + returnValue);
     }
     // 访问属性
     @Test
     public void test1() throws Exception {
         // 1.根据属性名获取属性对象
         // Field filed = c.getField(name); //只能获取public修饰的属性,包含从父类继承来的,不限于直接父类
         Field field = c.getDeclaredField("name");
         field.setAccessible(true);
         // 2.获取对应类的对象
         Object obj = c.newInstance();
         // 3.为属性赋值
         field.set(obj, "慕容复");
         // 4.读取属性
         Object value = field.get(obj);
         System.out.println(value);
         // -----------------------练习------------------
          System.out.println(field.get(c.newInstance()));
     }
     // 访问静态属性
     @Test
     public void exec1() throws Exception {
         // 1.根据属性名获取属性对象
         Field field = c.getDeclaredField("SCHOOL");
         // 2.暴破
         field.setAccessible(true);
         // 3.为属性赋值
         // field.set(null, "北京大学");
         // 4.访问属性
         System.out.println(field.get(null));
     }





































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值