java的反射可以绕过访问权限,访问到类的非公有方法和成员,利用反射还可以访问内部类、匿名内部类的私有属性。可能这点会引起安全性的讨论。反射的使用帮助解决很多复杂的问题,其运行时的类型检查,动态调用,代理的实现等,反射为我们写程序带来了很大的灵活性,很多功能都是基于反射。
一、实体类
package cn.moving.reflect; import java.io.InputStream; import java.util.List; public class Person { private String name = "maomao"; private int password; private static int age = 23; private static final Person instance = new Person(); public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPassword() { return password; } public void setPassword(int password) { this.password = password; } public static int getAge() { return age; } public static void setAge(int age) { Person.age = age; } private Person() { System.out.println("person"); } public static Person getInstance() { return Person.instance; } public Person(String name) { this.name = name; System.out.println("person name"); } public Person(String name, int age) { System.out.println("姓名:" + name + "年龄:" + age); } public Person(int age) { System.out.println("age"); } public Person(List list) { System.out.println("list"); } public void play(String name, int age) { System.out.println("姓名:" + name + "年龄:" + age + "正在玩"); } public Class[] aa(String name, int[] password) { return new Class[] { String.class }; } private void bb(InputStream is) { System.out.println(is); } public static void cc(int num) { System.out.println(num); } public static void main(String args[]) { for (String s : args) { System.out.println(s); } } }
二、反射字段
package cn.moving.reflect; import java.lang.reflect.Field; import org.junit.Test; public class ReflectField { /** * 反射类的字段 * @throws Exception * @throws SecurityException */ // 解剖(=反射)private String name = "maomao"; // 私有字段 @Test public void reflectName() throws SecurityException, Exception { Class clazz = Class.forName("cn.moving.reflect.Person"); Field f = clazz.getDeclaredField("name"); f.setAccessible(true); Person p = new Person("haha"); Object value = f.get(p); Class type = f.getType(); System.out.println(type); if (type.equals(String.class)) { String name_value = (String) value; System.out.println(name_value); } f.set(p, "LanWenTao"); System.out.println(f.get(p)); } @Test // private static int age = 23;静态私有的属性 public void reflectAge() throws Exception { Class clazz = Class.forName("cn.moving.reflect.Person"); Field f = clazz.getDeclaredField("age"); f.setAccessible(true); System.out.println(f.get(null));; } }
三、反射构造方法
package cn.moving.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import org.junit.Test; public class ReflectConstructor { /** * 反射构造方法 * * @throws ClassNotFoundException * @throws InvocationTargetException * @throws IllegalAccessException * @throws InstantiationException * @throws IllegalArgumentException */ @Test public void reflectNoArgumentConstrustor() throws Exception { Class clazz = Class.forName("cn.moving.reflect.Person"); Constructor[] cons = clazz.getDeclaredConstructors(); Constructor c = null; for (Constructor con : cons) { con.setAccessible(true); c = con; } Person p = (Person) c.newInstance(null); System.out.println(p.getName()); } @Test public void reflectConstructor() throws Exception { Class clazz = Class.forName("cn.moving.reflect.Person"); Constructor c = clazz.getConstructor(String.class, int.class); Person p = (Person) c.newInstance("XiaoMing", 22); System.out.println(p.getName());// ??????????? } }
四、反射普通方法
package cn.moving.reflect; import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; import org.junit.Test; public class reflectMethod { /** * 反射普通方法 */ // public void play(String name, int age) @Test public void reflectPlay() throws Exception { Class clazz = Class.forName("cn.moving.reflect.Person"); Method method = clazz.getMethod("play", String.class, int.class); Person p = new Person("ZhangSan",22); method.invoke(p, "sdfdsf",44); } //public Class[] aa(String name, int[] password) @Test public void reflectClass() throws Exception{ Class clazz = Class.forName("cn.moving.reflect.Person"); Method method = clazz.getMethod("aa", String.class,int[].class); Person p = Person.getInstance(); Class[] cs =(Class[]) method.invoke(p, "ZhangSan",new int[]{12,332,4,23,4}); System.out.println(cs[0]); System.out.println(p.getName()); } @Test //private void bb(InputStream is) public void reflectbb() throws Exception{ Class clazz = Class.forName("cn.moving.reflect.Person"); Method method = clazz.getDeclaredMethod("bb", InputStream.class); method.setAccessible(true); Person p = Person.getInstance(); method.invoke(p, new FileInputStream("c:\\1.txt")); } @Test //public static void cc(int num) public void reflectcc() throws Exception{ Class clazz = Class.forName("cn.moving.reflect.Person"); Method method = clazz.getMethod("cc",int.class); method.invoke(null,34535);//静态不传对象也可以 } @Test //public static void main(String agrs[]) public void reflectMain()throws Exception{ Class clazz = Class.forName("cn.moving.reflect.Person"); Method method = clazz.getMethod("main", String[].class); // method.invoke(null,new String[]{"sdfds","sdfsd"}); //wrong // method.invoke(null,(Object)new String[]{"sd2342ds","sdfsd"});//ok method.invoke(null,new Object[]{new String[]{"sd2342ds","sdfsd"}});//true } }
注:main方法的参数是一个字符串数组,即public static void main(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainMethod.invoke(null,new String[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题。