博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
由浅到深理解java反射
阅读量:6005 次
发布时间:2019-06-20

本文共 6968 字,大约阅读时间需要 23 分钟。

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
arrayList1 = new ArrayList
(); 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(); } }}

 

转载于:https://www.cnblogs.com/garfieldcgf/p/5951130.html

你可能感兴趣的文章
面试110道题
查看>>
python 08 文件操作
查看>>
强势解决:windows 不能在本地计算机中起动Tomcat参考特定错误代码1
查看>>
Gradle 配置debug和release工程目录
查看>>
curl指令的使用
查看>>
LNAMP第二版(nginx 1.2.0+apache 2.4.2+php 5.4)
查看>>
MongoDB repl set权限认证配置步骤
查看>>
java学习笔记(1)
查看>>
禁止Mysql默认端口访问Internet - MySQL - IT技术网
查看>>
基于用户投票的排名算法(二):Reddit
查看>>
下午最后的草坪
查看>>
Maven学习总结(七)——eclipse中使用Maven创建Web项目
查看>>
用PHP读取和编写XML DOM4
查看>>
1.部分(苹果)移动端的cookie不支持中文字符,2.从json字符串变为json对象时,只支持对象数组...
查看>>
vim配置及快捷键
查看>>
[转载] win10进行端口转发
查看>>
利用JavaScript jQuery实现图片无限循环轮播(不借助于轮播插件)-----转载
查看>>
从零开始搭建vue项目 请求拦截器 响应拦截器
查看>>
HDU3257 Hello World!【打印图案+位运算】
查看>>
jquery 选择器
查看>>