Java反射的理解
一、Java内存模型
先了解一下JVM(虚拟机),java之所以能跨平台就是因为这个东西,你可以理解成一个进程,程序,只不过他的作用是用来跑你的代码的。
假如你写了一段代码:Object o=new Object();
运行了起来!
首先JVM会启动,你的代码会编译成一个.class文件,然后被类加载器加载进jvm的内存中,你的类Object加载到方法区中,创建了Object类的class对象到堆中,注意这个不是new出来的对象,而是类的类型对象,每个类只有一个class对象,作为方法区类的数据结构的接口。jvm创建对象前,会先检查类是否加载,寻找类对应的class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。
上面的流程就是你自己写好的代码扔给jvm去跑,跑完就over了,jvm关闭,你的程序也停止了。
为什么要讲这个呢?因为要理解反射必须知道它在什么场景下使用。
题主想想上面的程序对象是自己new的,程序相当于写死了给jvm去跑。假如一个服务器上突然遇到某个请求哦要用到某个类,哎呀但没加载进jvm,是不是要停下来自己写段代码,new一下,哦启动一下服务器!(这是傻子干的)
正确用法:
二、Java反射机制
含义:所谓的反射机制就是java语言在运行时拥有一项自观的能力。通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。
Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method。
Java反射的作用:在Java运行时环境中,对于任意一个类,可以知道这个类有哪些属性和方法。对于任意一个对象,可以调用它的任意一个方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
Java 反射机制主要提供了以下功能:
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法
三、Java反射用法
1、获取类对象的方法
Class<?> cl = Class.forName("java.lang.String");
Class<?> cl = String.class;
String str = "111";
Class<?> cl = str.getClass
2.获取字段信息的方法
Class<?> cl = String.class; //获取公有的指定成员变量(包括继承的公有变量都能访问到但是私有和受保护的属性访问不到) Field field = cls.getField("变量名"); //获取公有所有成员变量(私有的和受保护的访问不到) Field[] fields = cls.getFields(); //获取以声明的指定变量(私有、公有、受保护的都能访问到,但是不包括继承的) Field field1 = cls.getDeclaredField("变量名"); //获取所有以声明的变量 Field[] fields1 = cls.getDeclaredFields();
3、获取方法信息的方法
//返回某个类的指定的公用(public)方法,包括其继承类的公用方法。 Method method = cl.getMethod("方法名"); //返回某个类的所有公用(public)方法. Method[] methods = cl.getMethods(); //返回类或接口声明的指定方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。可以传方法名和方法的参数类型,多个参数逗号隔开。 Method method = cl.getDeclaredMethod("方法名", String.class); //返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 Method[] methods = c.getDeclaredMethods();
4、获取构造器的方法
//获取该Class对象公有的使用特殊参数类型的构造函数,与父类构造无关 Constructor<?> constructor = cl.getConstructor(参数类型); //获取该Class对象所有公有的构造函数 Constructor[] constructors = c.getConstructors(); //获取该Class对象指定的声明的构造函数包括公有、私有、受保护的,与父类构造无关 Constructor<?> constructor1 = c.getDeclaredConstructor(参数类型) //获取该Class对象所有声明的构造函数 Constructor[] constructors1 = c.getDeclaredConstructors();
四、总结
当我们用getDeclaredField("变量名")获取到声明指定变量时,直接修改该属性的值时,需要调用field.setAccessible(true),这时才能修改该变量的值,因为该变量可能是私有的或者是受保护的不允许直接修改,而当我们这样做了就违背了java面向对象封装的原则,并且在有些业务上当你不了解有些私有属性不能被修改时,你就可以通过反射获取该类的所有set方法,通过调用set方法去改变具体属性值。
这个是用来将字符串首字母转大写的方法,进行字母的ascii编码前移
//将传进来的字段名首字母大写 private static String getMethodName(String fildeName) throws Exception{ byte[] items = fildeName.getBytes(); items[0] = (byte) ((char) items[0] - 'a' + 'A'); return new String(items); }