Java反射机制
一:何为反射机制
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
二,反射机制的作用:
1,反编译:.class-->.java
2,通过反射机制访问java对象的属性,方法,构造方法等;
这样好像更容易理解一些,下边我们具体看怎么实现这些功能。
三,在这里先看一下sun为我们提供了那些反射机制中的类:
java.lang.Class;
java.lang.reflect.Constructor; java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
学会了这个,理解Spring的话,就简单很多。
1,反射机制获取类有三种方法,
//例程1:获取方法
//方法一: //获得类类型的两种方式 Class classType = Class.forName("com.sun.Role"); //返回class对象所对应的类或接口中,所声明的所有方法的数组(包括私有方法) System.out.println("classType="+classType.getSimpleName()); //类名 System.out.println("classType="+classType.getCanonicalName());//类的全名 //方法二: Class classType2 = com.sun.Role.class; System.out.println("classType2="+classType2.getSimpleName()); System.out.println("classType2="+classType2.getCanonicalName());
这里说的还有一个方法,不过最后一个方法觉得有点傻
//方法三:
Class classType3 = new Role().getClass(); System.out.println("classType3="+classType3.getSimpleName()); System.out.println("classType3="+classType3.getCanonicalName());
2,创建对象:获取类以后我们来创建它的对象,利用newInstance:
//例程2:创建对象 Object obj = classType.newInstance();
3,获取属性:分为所有的属性和指定的属性
a,先看获取所有的属性的写法:
//获取属性:分为所有的属性和指定的属性: Field[] fs = classType.getDeclaredFields(); //定义可变长的字符串,用来存储属性 StringBuffer sb = new StringBuffer(); sb.append(Modifier.toString(classType.getModifiers()) + " class " + classType.getSimpleName() +"{\n"); for(Field field:fs){ sb.append("\t");//空格 sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等 sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字 sb.append(field.getName()+";\n");//属性的名字+回车 } sb.append("}"); System.out.println(sb);
b.获得特定的属性,然后进行修改
//获取age属性 Field age = classType.getDeclaredField("age"); Field name = classType.getDeclaredField("name"); //打破封装 age.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。 name.setAccessible(true); System.out.println("Role class age is = "+age.get(obj)); System.out.println("Role class age is = "+name.get(obj)); age.set(obj, "110"); //set System.out.println("Role class age is = "+age.get(obj));
4.获取方法的类型和返回值
Method[] methods = classType.getDeclaredMethods(); StringBuffer sb2 = new StringBuffer(); //遍历输出所有方法声明 for(Method method : methods) { sb2.append("\t");//空格 sb2.append(Modifier.toString(method.getModifiers())+" ");//获得方法的类型 sb2.append(method.getReturnType().getSimpleName().toString()+" ");//获得方法的返回类型 sb2.append(method.getName()+"();\n");//获取方法名 } System.out.println(sb2);
详情可以去见API,基本上可以通过反射机制,在知道一个类的名字后,反编译出该类文件为.java文件。
5.通过反射机制调用方法
// 通过反射调用方法 //调用方法一: // 首先需要获得与该方法对应的Method对象 Method toMyStringMethod = classType.getDeclaredMethod("toMyString",new Class[]{String.class}); toMyStringMethod.setAccessible(true); Object result2 = toMyStringMethod.invoke(obj, new Object[]{"sun"});//为该方法传入参数 System.out.println(result2.toString());
//调用方法二: Method toMyStringMethod1 = classType.getMethod("toMyString",new Class[]{String.class}); Object result = toMyStringMethod1.invoke(obj, new Object[] {"xxxx"}); System.out.println(result); // 此时result是Integer类型
到此,反射机制完毕,Spring里面通过配置文件也是差不多的,能够通过配置文件读取到方法和属性,加以运用。
下面是实例的两份完整代码:
package com.sun; /** * A base class having some attributes and methods * @author Octobershiner * @since 2012 3 17 * * */ public class Role { public String age = "10"; private String name = "Hello world"; private String type; // Constructors public Role(){ System.out.println("Constructor Role() is invoking"); } //私有构造器 private Role(String name){ this.name = name; System.out.println("Constructor Role(String name) is invoking."); } //get and set method public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } //override the toString method to show the class public String toMyString(String xxx){ return "This is a role called "+xxx; } }
和
package com.sun; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.omg.Dynamic.Parameter; public class TESTreflection { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException { //例程1:获取方法 //获得类类型的两种方式 Class classType = Class.forName("com.sun.Role"); //返回class对象所对应的类或接口中,所声明的所有方法的数组(包括私有方法) System.out.println("classType="+classType.getSimpleName()); //类名 System.out.println("classType="+classType.getCanonicalName());//类的全名 //例程2:创建对象 Object obj = classType.newInstance(); //获取属性:分为所有的属性和指定的属性: Field[] fs = classType.getDeclaredFields(); //定义可变长的字符串,用来存储属性 StringBuffer sb = new StringBuffer(); sb.append(Modifier.toString(classType.getModifiers()) + " class " + classType.getSimpleName() +"{\n"); for(Field field:fs){ sb.append("\t");//空格 sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等 sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字 sb.append(field.getName()+";\n");//属性的名字+回车 } sb.append("}"); System.out.println(sb); //获取age属性 Field age = classType.getDeclaredField("age"); Field name = classType.getDeclaredField("name"); //打破封装 age.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。 name.setAccessible(true); System.out.println("Role class age is = "+age.get(obj)); System.out.println("Role class age is = "+name.get(obj)); age.set(obj, "110"); //set System.out.println("Role class age is = "+age.get(obj)); Method[] methods = classType.getDeclaredMethods(); StringBuffer sb2 = new StringBuffer(); //遍历输出所有方法声明 for(Method method : methods) { sb2.append("\t");//空格 sb2.append(Modifier.toString(method.getModifiers())+" ");//获得方法的类型 sb2.append(method.getReturnType().getSimpleName().toString()+" ");//获得方法的返回类型 sb2.append(method.getName()+"();\n");//获取方法名 } System.out.println(sb2); // 通过反射调用方法 //调用方法一: // 首先需要获得与该方法对应的Method对象 Method toMyStringMethod = classType.getDeclaredMethod("toMyString",new Class[]{String.class}); toMyStringMethod.setAccessible(true); Object result2 = toMyStringMethod.invoke(obj, new Object[]{"sun"});//为该方法传入参数 System.out.println(result2.toString()); //调用方法二: Method toMyStringMethod1 = classType.getMethod("toMyString",new Class[]{String.class}); Object result = toMyStringMethod1.invoke(obj, new Object[] {"xxxx"}); System.out.println(result); // 此时result是Integer类型 /* //例程2:通过反射调用方法 // 生成新的对象:用newInstance()方法 Class<?> classType2 = classType.getName().toString(); // 通过反射调用方法 // 首先需要获得与该方法对应的Method对象 Method echoMethod = role.getDeclaredMethod("echo", new Class[]{String.class}); */ } }