JAVA反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java的反射机制。

  • Java反射的作用?

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

  • Class类的使用

    • OOP的世界里,万事万物皆对象。类是谁的对象呢?——类是对象,类是java.lang.Class类的实例对象!There is a class named class.
    • 实例:
    • //有一个类
      class Foo {
      void print() {System.out.println("Foo");}
      } //在main函数里:
      public static void main(String[] args) {
      //Foo这个类也是一个实例对象,Class类的实例对象,如何表示呢 //任何一个类都是Class类的实例对象,这个实例对象有三种表示方式
      //1. --实际在告诉我们,任何一个类都有一个隐含的静态成员变量-class
      Class c1 = Foo.class; //2. 已知该类的对象通过getClass 方法
      Foo f1 = new Foo();
      Class c2 = f1.getClass(); //c1, c2表示了Foo类的类类型(class type)
      //指类也是一个对象,是class类的实例对象,这个对象就成为该类的类类型 //不管从c1,c2都代表了Foo类的类类型,一个类只可能是Class类的一个实例对象
      System.out.println(c1 == c2); //true //3.
      Class c3 = null;
      try {
      c3 = Class.forName("com.immoc.reflect.Foo");
      } catch (ClassNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      System.out.println(c3 == c2); //true /*
      * 我们可以通过类的类类型创建对象实例;
      * 通过c1 or c2 or c3创建Foo类的对象
      */
      try {
      Foo foo = (Foo)c1.newInstance(); //需要有无参的构造方法
      foo.print();
      } catch (InstantiationException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      } catch (IllegalAccessException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      }
    • 动态加载类:例如Class.forName("类的全称")不仅表示了类的类类型,还代表了动态加载类
      • 编译时刻加载类是静态加载类、运行时加载类是动态加载
      • new 对象是静态加载类,在编译时刻就需要加载所有可能使用到的类
      • 动态加载类:
        • Class c = Class.forName(args[0]);
        • OfficeAble oa = (OfficeAble)c.newInstance(); //通过类类型创建该类的对象实例
      • 功能性的类尽量使用动态加载,而非静态加载
    • 基本的数据类型,void关键字 都存在类类型
    • Class类的基本API操作
    • /**
      * 打印类的信息,包括类的成员函数,成员变量
      * @param obj
      */
      public static void printClassMessage(Object obj) {
      //要获取类的信息,首先要获取类的类类型
      Class c = obj.getClass();//传递的是哪个子类的对象,c就是该类的类类型
      System.out.println("类的名称是:" + c.getName());
      /*
      * Method类,方法对象
      * 一个成员方法就是一个Method对象
      * getMethod()方法获取的是所有public的函数,包括父类继承而来的
      */
      Method[] ms = c.getMethods();
      for(Method m : ms) {
      //得到方法返回值类型的类类型
      Class returnType = m.getReturnType();
      System.out.print(returnType.getName() + " ");
      System.out.print(m.getName() + "(");
      //获取参数类型——得到的是参数列表的类型的类类型
      Class[] paramTypes = m.getParameterTypes();
      for(Class p : paramTypes) {
      System.out.print(p.getName() + ",");
      }
      System.out.println(")");
      }
      }
  • 方法的反射
    • public static void printMethodMessage(Object obj) {
      //要获取类的信息,首先要获取类的类类型
      Class c = obj.getClass();//传递的是哪个子类的对象,c就是该类的类类型
      System.out.println("类的名称是:" + c.getName());
      /*
      * Method类,方法对象
      * 一个成员方法就是一个Method对象
      * getMethod()方法获取的是所有public的函数,包括父类继承而来的
      */
      Method[] ms = c.getMethods();
      for(Method m : ms) {
      //得到方法返回值类型的类类型
      Class returnType = m.getReturnType();
      System.out.print(returnType.getName() + " ");
      System.out.print(m.getName() + "(");
      //获取参数类型——得到的是参数列表的类型的类类型
      Class[] paramTypes = m.getParameterTypes();
      for(Class p : paramTypes) {
      System.out.print(p.getName() + ",");
      }
      System.out.println(")");
      }
      }
    • 如何获取某个方法
      • 方法的名称和方法的参数列表才能唯一决定某个方法
    • 方法反射的操作
      • method.invoke(对象,参数列表)
      • public class MethodDemo1 {
        public static void main(String[] args) {
        /*
        * 要获取print(int, int)方法
        * 首先获取类的信息(类的类信息)
        */
        A a1 = new A();
        Class c = a1.getClass();
        //2. 获取方法,名称和参数列表
        try {
        Method m = c.getDeclaredMethod("print", new Class[]{int.class, int.class});
        //方法的反射操作:用对象调用方法
        m.invoke(a1, new Object[]{10, 20}); } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        } }
        } class A {
        public void print(int a, int b) {
        System.out.println(a + b);
        }
        public void print(String a, String b) {
        System.out.println(a.toUpperCase() + "," + b.toLowerCase());
        }
        }
  • 成员变量的反射
    •  成员变量也是对象,java.lang.reflect.Field, Field类封装了关于成员变量的操作
    • getFields()方法获取的是所有的public的成员变量的信息
    • getDeclaredFields()获取的是该类自己声明的所有成员变量的信息
    • //首先得到类型,然后得到该变量的名称:
      //如:private int t;
      public static void printFieldMessage(Object obj) {
      System.out.println("---------------------------------------------");
      Class c = obj.getClass(); Field[] fs = c.getDeclaredFields();
      for(Field f : fs) {
      //得到成员变量的类型的类类型 :int
      Class fieldType = f.getType();
      String typeName = fieldType.getName();
      //得到成员变量的名称 :t
      String fieldName = f.getName();
      System.out.println("typeName: " + typeName + " fieldName: " + fieldName);
      }
      }
  • 构造函数的反射
    • /**
      * 打印构造函数的信息(构造函数也是对象:java.long.Constructor)
      * @param obj
      */
      public static void printConMessage(Object obj) {
      Class c = obj.getClass();
      Constructor[] cs = c.getDeclaredConstructors();
      for(Constructor con : cs) {
      System.out.print(con.getName() + "(");
      //获取参数列表
      Class[] paramTypes = con.getParameterTypes();
      for(Class cl : paramTypes) {
      System.out.print(cl.getName() + ",");
      }
      System.out.println(")");
      }
      }
  • Java类加载机制
  • 通过反射了解集合泛型的本质
    • Java中集合的泛型是防止错误输入的,只在编译阶段有效,编译完之后就无效了。验证:通过方法的反射
    • public static void main(String[] args) {
      // TODO Auto-generated method stub
      ArrayList l1 = new ArrayList();
      ArrayList<String> l2 = new ArrayList<String>();
      l1.add("hello");
      l1.add(2); //wrong?是跟JDK版本有关系嘛???
      Class c1 = l1.getClass();
      Class c2 = l2.getClass();
      System.out.println(c1 == c2); //true,说明编译之后集合的泛型是去泛型化得
      //反射的操作都是编译之后的操作 try {
      Method m = c2.getMethod("add", Object.class);
      m.invoke(l1, "world");
      System.out.println(l1.size());
      } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }
      }

应用:通过类的名称来生产一个对象 如:Integer in = (Integer) class.forName(className).newInstance();

最新文章

  1. HOW TO RUN A SPRINT PLANNING MEETING (THE WAY I LIKE IT)
  2. thinkphp 模型、控制器、视图
  3. 关于php中正则匹配包括换行符在内的任意字符的问题总结
  4. haha
  5. Javascript中数组
  6. 浅谈JS DDoS攻击原理与防御
  7. MVC 后台DataTable 前台遍历
  8. HTML构成及基本标签
  9. [SOJ] shortest path in unweighted graph
  10. C++ 进制转换 十进制十六进制八进制二进制相互转换
  11. PAT 1152 Google Recruitment
  12. 谈谈逆向android里面的so
  13. Mac 系统安装教程
  14. 设置 WPF 的内容支持触摸直接滚动
  15. apache2.4 文件浏览服务器页面配置
  16. CentOS7修改默认启动级别
  17. 微信小程序开发——设置默认图片、错误加载图片
  18. node.js global object,util and so on
  19. Unity 基础-------------------------关于Anchor锚点的理解
  20. SQL SERVER 2008 误删数据且无全备恢复方法

热门文章

  1. 【解决】MongoDB 线上业务处理,数据去重脚本实现
  2. 【控制连接实现信息共享---linux和设备下ssh和远程连接telnet服务的简单搭建】
  3. js中split()和join()的用法
  4. laravel -- 路由
  5. python学习——装饰器函数
  6. R语言学习笔记(一):mode, class, typeof的区别
  7. 【动态规划】[UVA1025]A Spy in the Metro 城市里的间谍
  8. fastDFS 上传 java源码
  9. 2648: SJY摆棋子
  10. es同步mysql同步-logstash