暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

JAVA拾遗系列之JAVA基础-反射

尚浩宇 2022-01-11
174

一、概述

    反射,指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对任意一个对象,都能调用它的任意一个方法。这种动态获取信息,以及动态调用对象方法的功能,叫做java语言的反射机制。很多框架,比如ORM映射框架Hibernate就大量运用了反射,通过反射可以获取到Entity里配置的表名,字段名,表关系等等,然后生成数据库sql、填充数据等等。

    通过反射概括性的可以分为获取属性、获取注解、获取泛型、执行方法、修改属性值等几类。

二、获取属性

    给定一个对象,可以获取对象内的属性值,无论是否是私有,都可以获取,示例代码如下:

   
     public static void readAttributeValue(Object obj){
    String nameVlues="";
    //得到class
    Class cls = obj.getClass();
    //得到所有属性
    Field[] fields = cls.getDeclaredFields();
    for (int i=0;i<fields.length;i++){//遍历
    try {
    //得到属性
    Field field = fields[i];
    //打开私有访问
    field.setAccessible(true);
    //获取属性
    String name = field.getName();
    //获取属性值
    Object value = field.get(obj);
    //一个个赋值
    nameVlues += field.getName()+":"+value+",";
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    }
    }
    }


    三、获取注解

        写在属性或者类上等其它地方的注解,也可以用反射获取到,示例代码如下:


      public static <T> void parseMethod(Class<T> clazz) {
      try {
      T obj = clazz.newInstance();
      for (Method method : clazz.getDeclaredMethods()) {
      MyMethodAnnotation methodAnnotation = method.getAnnotation(MyMethodAnnotation.class);
      if (methodAnnotation != null) {
      // 通过反射调用带有此注解的方法
      method.invoke(obj, methodAnnotation.uri());
      }
      MyClassAndMethodAnnotation myClassAndMethodAnnotation = method
      .getAnnotation(MyClassAndMethodAnnotation.class);
      if (myClassAndMethodAnnotation != null) {
      if (EnumType.util.equals(myClassAndMethodAnnotation.classType())) {
      System.out.println("this is a util method");
      } else {
      System.out.println("this is a other method");
      }
      System.out.println(Arrays.toString(myClassAndMethodAnnotation.arr()));// 打印数组
      System.out.println(myClassAndMethodAnnotation.color());// 输出颜色
      }
      System.out.println("\t\t-----------------------");
      }
      } catch (Exception e) {
      e.printStackTrace();
      }
      }
      public static <T> void parseType(Class<T> clazz) {
      try {
      MyClassAndMethodAnnotation myClassAndMethodAnnotation = clazz
      .getAnnotation(MyClassAndMethodAnnotation.class);
      if (myClassAndMethodAnnotation != null) {
      if (EnumType.util.equals(myClassAndMethodAnnotation.classType())) {
      System.out.println("this is a util class");
      } else {
      System.out.println("this is a other class");
      }
      }
      MyClassAnnotation myClassAnnotation = clazz.getAnnotation(MyClassAnnotation.class);
      if (myClassAnnotation != null) {
      System.err.println(" class info: " + myClassAnnotation.uri());
      }
      } catch (Exception e) {
      e.printStackTrace();
      }


      }


      public static void main(String[] args) {
      parseMethod(TestAnnotation.class);
      parseType(TestAnnotation.class);
      }



      四、获取泛型

          如果属性或者类有用到泛型,也可以通过反射或者到泛型,示例代码如下:


        public static void getType() throws Exception {
        Class<GenericTest> clazz = GenericTest.class;
        Field f = clazz.getDeclaredField("score");
        // 直接使用getType()取出的类型只对普通类型的成员变量有效
        Class<?> a = f.getType();
        // 下面将看到仅输出java.util.Map
        System.out.println("score的类型是:" + a);
        // 获得成员变量f的泛型类型
        Type gType = f.getGenericType();
        // 如果gType类型是ParameterizedType对象
        if(gType instanceof ParameterizedType)
        {
        // 强制类型转换
        ParameterizedType pType = (ParameterizedType)gType;
        // 获取原始类型
        Type rType = pType.getRawType();
        System.out.println("原始类型是:" + rType);
        // 取得泛型类型的泛型参数
        Type[] tArgs = pType.getActualTypeArguments();
        System.out.println("泛型信息是:");
        for (int i = 0; i < tArgs.length; i++)
        {
        System.out.println("第" + i + "个泛型类型是:" + tArgs[i]);
        }
        }
        else
        {
        System.out.println("获取泛型类型出错!");
        }
        }


        五、执行方法

            对象内的方法,也可以进行调用,示例代码如下:


           public static void invokeMethod() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
          Foo foo = new Foo("这个一个Foo对象!");
          Class clazz = foo.getClass();
          Method m1 = clazz.getDeclaredMethod("outInfo");
          Method m2 = clazz.getDeclaredMethod("setMsg", String.class);
          Method m3 = clazz.getDeclaredMethod("getMsg");
          m1.invoke(foo);
          m2.invoke(foo, "重新设置msg信息!");
          String msg = (String) m3.invoke(foo);
          System.out.println(msg);
          }



          六、修改属性

              如果对象没有类似setter、getter的方法,也可以直接修改属性值,示例代码如下:


            public static void setField(){
            Class<Test> aClass = =Test.class;
            Field field = null;
            try {
            field = aClass.getDeclaredField("a");
            //将私有属性开发可修改
            field.setAccessible(true);
            field.set(this, 1000.0);
            Object o = field.get(this);
            System.err.println(o);
            } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
            }
            }


            有兴趣的大佬大神可以关注下小弟的微信公共号,一起学习交流,扫描以下二维码关注即可。


            文章转载自尚浩宇,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

            评论