由浅到深理解java反射

1.基础概念

  class类:

  1.1java是面向对象的,但是在java中存在两种东西不是面向对象的

    一种是普通的数据类型,这也是封装数据类存在的原因.

    二种是静态静态成员.

  1.2所以我们首先要理解,类也是一种对象,类是java.lang.Class类的对象.

  1.3反射的操作其实是执行了编译,获得了类的编译信息,也就是字节码.

  1.4获取类类型可以有三种方式:

DemoGetClassType.java
/**
 * Created by garfield on 2016/10/11.
 * 三种方式获得类类型
 */
public class DemoGetClassType {
    public static void main(String[] args) {
        //car是一个对象
        Car car = new Car();
        //那么既然Car类型为一个对象,那么如何表示Car这个类:
        //查看Class源码发现类是有构造方法的,但是是私有的,只有java虚拟机才能创建Class实例,所以我们要通过其他方法来表示类对象
        //类是Class的实例对象,称之为该类的类类型(class type)

        //可以有三种写法
        //第一种:每一个类都有一个静态成员:class
        Class c1 = Car.class;

        //第二种:利用getClass()方法
        Class c2 = car.getClass();

        //类类型是相等的
        System.out.println(c1 == c2);
        Class c3 = null;
        try {
            c3 = Class.forName("com.learn.reflect.a_GetClassType.Car");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(c2 == c3);

        //通过类类型可以创建类实例,其实际是通过调用类的无参构造方法,
        try {
            Car car1 = (Car)c1.newInstance();
            car1.run();
        } catch (InstantiationException e) {
            //如果丢失无参构造方法,抛出InstantiationException,也就是实例化异常
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }
}
class Car {

    void run(){
        System.out.println("i can run");
    }
}

2.动态加载类

  2.1在类对象的forName()方法中,是可以表示动态加载类的,此处区分:

    一,在编译时刻加载的类是静态加载类

    二,运行时刻加载类是动态加载类

  2.2利用动态时刻加载可以避免一个功能出错的时候整个系统都不能运行

DemoStaticLoad.java
/**
 * Created by garfield on 2016/10/13.
 */
public class DemoStaticLoad {

    public static void main(String[] args) {
        //new创建对象 是静态加载类,在编译时刻就需要加载任何可能使用到的类
        //这个类当中,由于都是new加载,所以当bus或者jeep有任何一个类不存在时,编译报错
        //此时应当考虑使用动态加载,尤其是当类数量多的时候
        if("bus".equals(args[0])){
            Bus bus = new Bus();
            bus.start();
        }
        if("jeep".equals(args[0])){
            Jeep jeep = new Jeep();
            jeep.start();
        }
    }
}

DemoDynasticLoad.java

/**
 * Created by garfield on 2016/10/13.
 */
public class DemoDynasticLoad {

    public static void main(String[] args) {
        try {
            //动态加载类,在运行时刻编译,只有当运行类不存在时才会报错
            //但凡这种多功能编程,都应该设计成这种不用非重新编译不可的结构
            Class Wheel = Class.forName(args[0]);
            Wheel wheel = (Wheel) Wheel.newInstance();
            wheel.start();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

3.获取类的信息

  3.1普通的数据类型以及void同样存在类类型

  3.2可以获取类的方法,成员变量,构造函数,包名,父类,接口等信息

DemoGetClassInformation.java
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * Created by garfield on 2016/10/13.
 * 打印出关于输入类型的方法和参数,成员变量,构造函数
 */
public class DemoGetClassInformation {
    public static void main(String[] args) {
        printClassInformation("aa");
        printClassInformation(11);
    }

    static void printClassInformation(Object obj) {
        Class objClass = obj.getClass();
        System.out.println(objClass.getName());
        //获取不带前缀的类名
        System.out.println(objClass.getSimpleName());
        /**
         * 看源码可以看出,getMethods返回了所有的public方法,其中包括继承而来的方法
         * 如果想获取本身的所有方法,用getDeclaredMethods()
         */
        Method[] methods = objClass.getMethods();

        for (Method method : methods) {
            System.out.println("================================");
            System.out.println("方法名称是" + method.getName());
            System.out.println("返回值是:" + method.getReturnType().getName());
            //获取参数列表,返回值是参数的类类型
            Class[] params = method.getParameterTypes();
            for (Class param : params) {
                System.out.println("参数:" + param.getName());
            }
        }
        /**
         * java.lang.reflect.Field封装了成员变量
         * 与方法相仿,getFields()获得的是public变量,如果要获取本身声明的私有变量,采用getDeclaredFields()
         */
        System.out.println("=======打印成员变量=======");
        Field[] fields = objClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println("成员变量类型:" + field.getType().getName() + ", 成员变量名" + field.getName());
        }

        /**
         * java.lang.Constructor封装构造函数
         * 与上述相仿,getConstructors()得到public构造函数,getDeclaredConstructors()获得声明构造函数
         */
        System.out.println("=======打印构造函数=======");
        Constructor[] constructors = objClass.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("构造函数名" + constructor.getName());
            Class[] conParas = constructor.getParameterTypes();
            for (Class conPara : conParas) {
                System.out.println("参数:" + conPara.getName());
            }

        }
    }
}

4.方法的反射

  4.1需要理解方法反射的操作 method.invoke(对象,参数列表)

  4.2调用方法是传入的是实例和参数

DemoMethodReflection.java
/**
 * Created by garfield on 2016/10/13.
 * 方法反射实例
 */
public class DemoMethodReflection {
    public static void main(String[] args) {
        //先得到类信息
        MathCount mathCount = new MathCount();
        Class mathCountClass = mathCount.getClass();
        try {
            /**
             * 获得方法,然后进行方法反射,如果有返回值可以获得返回值
             * 注意可变参数两种写法
             * 1.new class[]{int.class,int.class}
             * 2.int.class,int.class
             */
            Method method =  mathCountClass.getMethod("add",new Class[]{int.class,int.class});
            method.invoke(mathCount,new Object[]{22,44});
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }

}
class MathCount {

    public void add(int a, int b){
        System.out.println(a + b);
    }
}

5.集合的本质有助于我们理解方法反射和正常调用的不同(反射时绕过了编译)

  5.1集合中通过反射可以放入不同类型的元素

  5.2不同泛型的集合,其本质是同一个类类型

DemoSetNature.java

/**
 * Created by garfield on 2016/10/13.
 */
public class DemoSetNature {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        ArrayList<String> arrayList1 = new ArrayList<String>();
        Class arrayListClass = arrayList.getClass();
        Class arrayList1Class = arrayList1.getClass();
        System.out.println(arrayList1Class == arrayListClass);
        /**
         * 结果为true说明,编译之后集合的泛型是去泛型化的
         * 泛型只在编译阶段有效
         */
        try {
            Method method = arrayListClass.getMethod("add",Object.class);
            //!绕过编译之后可以添加其他类型的数据
            method.invoke(arrayList1,200);
            System.out.println(arrayList1);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}
时间: 2025-01-07 11:31:56

由浅到深理解java反射的相关文章

通过案例一步学习理解java反射机制

java 反射机制 以下只是个人在学习反射过程中的笔记,如有错误请指出纠正. 1. 通过例子理解反射 获取类的类类型的三种方法 package Reflect; public class ClassReflect { public static void main(String[] args) { ClassReflect cr = new ClassReflect(); //方法一: Class c = cr.getClass(); //方法二: Class c1 =ClassReflect.

由浅入深理解----java反射技术

java反射机制详解 java反射机制是在运行状态下,对任意一个类可以获取该类的属性和方法,对任意一个对象可以调用其属性和方法.这种动态的获取信息和调用对象的方法的功能称为java的反射机制 class<?>类,在java.lang包下面,class类的实例表示正在运行的java应用程序中的类和接口                                      ?.class是一个类,一个描述类的类(也就是描述类的本身),封装了描述字段的Field.方法Method和构造器的Con

深入理解Java反射

要想理解反射的原理,首先要了解什么是类型信息.Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息:另一种是反射机制,它允许我们在运行时发现和使用类的信息. 1.Class对象 理解RTTI在Java中的工作原理,首先需要知道类型信息在运行时是如何表示的,这是由Class对象来完成的,它包含了与类有关的信息.Class对象就是用来创建所有"常规"对象的,Java使用Class对象来执行RTTI,即使你正在执行的是类似

由浅到深理解ROS(1)

ROS机器人操作系统 ( Robot Operating System 或简称 ROS),可以帮助提高机器人软件的开发效率.ROS能够提供类似传统操作系统的诸多功能,如硬件抽象.底层设备控制.常用功能实现.进程间消息传递和程序包管理等.此外,它还提供相关工具和库,用于获取.编译.编辑代码以及在多个计算机之间运行程序完成分布式计算.结合笔者对ROS的理解,想与大家一起讨论,共同把ROS理解的更准确,一起进步. 对ROS的误解: 1.ROS不是一种编程语言.实际上,ROS的主要代码由C++语言编写,

如何理解java反射?

一.反射基本概念 反射之中包含了一个"反"的概念,所以要想解释反射就必须先从"正"开始解释,一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产生实例化对象,但是"反"指的是通过对象找到类. packagecn.mldn.demo; class Person { } public class TestDemo { public static void main(String[] args) throws Exception { P

(转)由浅到深理解ROS(5)- launch启动文件的理解与编写

ROS提供了一个同时启动节点管理器(master)和多个节点的途径,即使用启动文件(launch file).事实上,在ROS功能包中,启动文件的使用是非常普遍的.任何包含两个或两个以上节点的系统都可以利用启动文件来指定和配置需要使用的节点.通常的命名方案是以.launch作为启动文件的后缀,启动文件是XML文件.一般把启动文件存储在取名为launch的目录中. 每个XML文件都必须要包含一个根元素.根元素由一对launch标签定义:<launch> - <launch>元素都应该

由浅到深理解ROS(3)-命名空间

全局命名空间:/rosout前面的反斜杠“/”表明该节点名称属于全局命名空间.之所以叫做全局名称因为它们在任何地方(包括代码.命令行工具.图形界面工具等的任何地方)都可以使用.无论这些名称用作众多命令行工具的参数还是用在节点内部,它们都有明确的含义.这些名称从来不会产生二义性,也无需额外的上下文信息来决定名称指的哪个资源.如/turtle1/cmd_vel 由斜杠分开的一系列命名空间(namespace),每个斜杠代表一级命名空间.命名空间用于将相关的计算图源(节点.话题.服务和参数统称为计算图

封装jdbc让你轻松理解Java反射机制

1.目录结构 2.BasicDao.java static{ try { Class.forName("com.mysql.jdbc.Driver"); } catch (Exception e) { e.printStackTrace(); } } public Connection getConnection() throws SQLException{ String url = "jdbc:mysql://127.0.0.1:3306/dbparam?autoRecon

由浅到深理解ROS(2)

ROS文件系统 用户可以直接参看官网:http://wiki.ros.org/ROS/Tutorials/NavigatingTheFilesystem ROS文件系统中的两个最基本的概念:Package和Manifest,即包和清单文件. (1)Package是组织ROS代码的最基本单位,每一个Package都可以包括库文件,可执行文件,脚本及其它的一些文件. (2)Manifest文件是对Package的相关信息的一个描述.他提供了Package之间的依赖性,以及一个包的元信息,比如版本.维