Java反射理解
序言
一般而言,动态语言是指程序运行时,允许改变程序结构或变量类型的语言。
从这个观点来看,Perl、Python、Ruby是动态语言,C++、Java、C#不是动态语言。
但是Java有动态相关机制:Reflection,反射,是指可以运行时加载、探知、使用编译期间完全未知的Classes。
一、什么是反射?
Java程序可以加载一个运行时才得知名称的Class,获取其完整构造,并生成其对象实体,设置属性,调用方法。
这种动态获取类信息以及动态调用对象方法的功能就是Java语言的反射机制。
二、反射的作用?
1、在运行时判断任意一个对象所属的类
2、在运行时构造任意一个类的对象
3、在运行时判断任意一个类所具有的成员变量和方法
4、在运行时调用任意一个对象的方法
三、反射的一些概念
1、反射相关的类和接口,都放在软件包java.lang.reflect
软件包java.lang.reflect提供类和接口,以获取关于类和对象的反射信息。
在安全限制内,反射允许编程访问关于加载类的字段、方法和构造方法的信息,并允许使用反射字段、方法和构造方法对对象上的基本对等项进行操作。
如果必需的 ReflectPermission 可用,则 AccessibleObject 允许抑制访问检查。Array 提供动态创建和访问数组的静态方法。
此包中的类以及 java.lang.Class 可以适应以下应用程序的需要:调试程序、解释程序、对象检查程序、类浏览程序等。
2、反射相关类摘要
类名 | 说明 |
AccessibleObject | AccessibleObject 类是Field、Method 和 Constructor 对象的基类。 |
Constructor<T> | Constructor提供关于类的单个构造方法的信息以及对它的访问权限。 |
Field | Field提供有关类或接口的单个字段的信息,以及对它的动态访问权限。 |
Method | Method提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。 |
Modifier | Modifier类提供了static方法和常量,对类和成员访问修饰符进行解码。 |
Proxy | Proxy提供用于创建动态代理类和实例的静态方法,它还是由这些方法创 建的所有动态代理类的超类。 |
ReflectPermission | 反射操作的Permission类。 |
3、java.lang.Class说明
Class 类和一般类一样继承自 Object ,其实体用以表达 Java 程序运行时的类和接口,枚举,数组,基础类型(boolean, byte, char, short, int, long, float, double)以及关键词void。
Class 没有公共构造方法。当一个 Class 被加载,或当加载器(class loader)的 defineClass() 被 JVM 调用, JVM 便自动产生一个类对象 。
Java 有个 Object 类,是所有 Java 类的继承根源,其内声明了数个应该在所有 Java 类中被改写的方法: hashCode()、equals()、clone() 、toString() 、getClass() 等。
其中 getClass() 返回一个 Class 类的对象,因此对于任意一个 Java 对象,都可以通过此方法获得对象的类型。
===Class 类是 Reflection API 中的核心类,它有以下方法===
getName() :获得类的完整名字。
getFields() :获得类的 public 类型的属性。
getDeclaredFields() :获得类的所有属性。
getMethods() :获得类的 public 类型的方法。
getDeclaredMethods() :获得类的所有方法。
getMethod(String name, Class[] parameterTypes) :获得类的特定方法, name 参数指定方法的名字, parameterTypes 参数指定方法的参数类型。
getConstructors() :获得类的 public 类型的构造方法。
getConstructor(Class[] parameterTypes) :获得类的特定构造方法, parameterTypes 参数指定构造方法的参数类型。
newInstance() :通过类的不带参数的构造方法创建这个类的一个对象。
四、反射的具体实现
反射用到的测试类:含测试用的方法和属性
package code.lemon; import java.util.Map; import java.util.Set; import java.util.List; public class Pear{ Map<String, String> map; public Set<String> set; public Class<?> clazz; String str; Set set1; public List<String> list; private static Pear pear; static{ pear = new Pear(); } private Pear(){ } public Pear(String str){ this.str = str; } public static void main(String [] args){ System.out.println(Pear.class.getPackage()); } public String getStr(){ return str; } private void setStr(String str){ this.str = str; } }
1、获取类的构造方法
public static void printConstructor(String className) { try { Class<?> clazz = Class.forName(className); //返回一个包含某些 Constructor 对象的数组, //这些对象反映此 Class 对象所表示的类的所有公共构造方法。 Constructor<?>[] constructors = clazz.getConstructors(); for (int i = 0; i < constructors.length; i++) { System.out.println(constructors[i]); } System.out.println("------------------"); //返回 Constructor 对象的一个数组, //这些对象反映此 Class 对象表示的类声明的所有构造方法。 Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); for (int i = 0; i < declaredConstructors.length; i++) { //返回此类或接口以整数编码的 Java 语言修饰符。 int modifiers = declaredConstructors[i].getModifiers(); System.out.println(declaredConstructors[i] + ":" + Modifier.toString(modifiers)); } } catch (Exception e) { } }
2、获取类属性
public static void printField(String className) { try { Class<?> clazz = Class.forName(className); //返回一个包含某些 Field 对象的数组, //这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。 Field[] fields = clazz.getFields(); for (int i = 0; i < fields.length; i++) { System.out.println(fields[i]); } System.out.println("------------------"); //返回 Field 对象的一个数组, //这些对象反映此 Class 对象所表示的类或接口所声明的所有字段, //包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段。 Field[] declaredFields = clazz.getDeclaredFields(); for (int i = 0; i < declaredFields.length; i++) { int modifiers = declaredFields[i].getModifiers(); System.out.println(declaredFields[i] + ":" + Modifier.toString(modifiers)); } } catch (Exception e) { } }
3、获取类方法
public static void printMethod(String className) { try { Class<?> clazz = Class.forName(className); //返回一个包含某些 Method 对象的数组, //这些对象反映此 Class 对象所表示的类或接口 //包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口的公共方法。 Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; i++) { System.out.println(methods[i]); } System.out.println("------------------"); //返回 Method 对象的一个数组, //这些对象反映此 Class 对象表示的类或接口声明的所有方法, //包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 Method[] declaredMethods = clazz.getDeclaredMethods(); for (int i = 0; i < declaredMethods.length; i++) { int modifiers = declaredMethods[i].getModifiers(); System.out.println(declaredMethods[i] + ":" + Modifier.toString(modifiers)); } } catch (Exception e) { } }
4、私有方法的调用
public static void invokeMethod(String className) { try { Class<?> clazz = Class.forName(className); //Pear pear = new Pear("hello"); Object pear = clazz.getConstructor(new Class[]{}).newInstance(new Object[]{}); //返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。 //name 参数是一个 String,它指定所需方法的简称, //parameterTypes 参数是 Class 对象的一个数组,它按声明顺序标识该方法的形式参数类型。 Method declaredMethod = clazz.getDeclaredMethod("setStr", new Class[]{String.class}); //对所有属性设置访问权限 当类中的成员变量为private时 必须设置此项 declaredMethod.setAccessible(true); //对带有指定参数的指定对象调用由此 Method 对象表示的基础方法。 declaredMethod.invoke(pear, new Object[]{"world"}); Method declaredMethod1 = clazz.getDeclaredMethod("getStr", new Class[]{}); Object result = declaredMethod1.invoke(pear, new Object[]{}); System.out.println((String)result); } catch (Exception e) { } }
5、动态创建、访问数组
public static void printArray() { try{ Class <?> classType = Class.forName("java.lang.String"); //newInstance创建此 Class 对象所表示的类的一个新实例。 Object array = Array.newInstance(classType, 10); Array.set(array, 5, "hello"); for(int i =0;i < Array.getLength(array);i ++){ String str = (String)Array.get(array,i); System.out.println(str); } }catch(Exception e){ } }
本例的包名为code.lemon,参数className为"code.lemon.Pear"
五、具体代码如下