Java 反射调用(Reflect)方法
反射机制是什么
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射机制能做什么
反射机制主要提供了以下功能:
-
在运行时判断任意一个对象所属的类;
-
在运行时构造任意一个类的对象;
-
在运行时判断任意一个类所具有的成员变量和方法;
-
在运行时调用任意一个对象的方法;
-
生成动态代理。
反射机制获取类的三种方法
//第一种方式: Class c1 = Class.forName("Student"); //第二种方式: //java中每个类型都有class 属性. Class c2 = Student.class; //第三种方式: //java语言中任何一个java对象都有getClass 方法 Student e = new Student(); Class c3 = e.getClass(); //c3是运行时类 (e的运行时类是Student)
创建对象
Class c = Class.forName("Student"); //创建此Class 对象所表示的类的一个新实例 Object obj = c.newInstance(); //调用了Student的无参数构造方法.
反射简单示例
反射调用一般分为3个步骤:
-
得到要调用类的class
-
得到要调用的类中的方法(Method)
-
方法调用(invoke)
TestReflect.java
package com.mimvp.reflect; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /* * 反射调用一般分为3个步骤: * 1. 得到要调用类的class * 2. 得到要调用的类中的方法(Method) * 3. 方法调用(invoke) * * @author mimvp.com * @date 2016.12.20 */ public class TestReflect { public TestReflect() { // TODO Auto-generated constructor stub } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Foo foo = new Foo("I am Foo Object"); Class clazz = foo.getClass(); // 1. 类名 Method m1 = clazz.getDeclaredMethod("outInfo"); // 2. 函数名 Method m2 = clazz.getDeclaredMethod("setMsg", String.class); // 2. 函数名 Method m3 = clazz.getDeclaredMethod("getMsg"); // 2. 函数名 m1.invoke(foo); // 3. invoke 类名 m2.invoke(foo, "Reset Msg Info"); // 3. invoke 类名 + 参数 String msg = (String)m3.invoke(foo); // 3. invoke 类名 System.out.println("m3 msg: " + msg); } } class Foo { private String msg; public Foo(String msg) { this.msg = msg; } public void setMsg(String msg) { this.msg = msg; } public String getMsg() { return this.msg; } public void outInfo() { System.out.println("This is Java Reflect Test Class"); } }
运行结果:
This is Java Reflect Test Class
m3 msg: Reset Msg Info
反射机制应用场景
1. 新建一个测试类
Student.java
package com.mimvp.reflect; public class Student { private String name; private int age; public void setName(String name) { this.name = name; } public String getName() { return this.name; } public void setAge(int age) { this.age = age; } public int getAge() { return this.age; } public static void hi(String name, int age) { System.out.println("hi, I am Name: " + name + ", Age: " + age); } }
2. 反射使用步骤
反射调用一般分为3个步骤:
-
得到要调用类的class
-
得到要调用的类中的方法(Method)
-
方法调用(invoke)
public static void test1() { try { Class cls = Class.forName("com.mimvp.reflect.Student"); Method m = cls.getDeclaredMethod("hi", new Class[]{String.class, int.class}); m.invoke(cls.newInstance(), "mimvp.com", 20); // 20 } catch (Exception e) { e.printStackTrace(); } }
3. 方法调用中的参数类型
在方法调用中,参数类型必须正确,这里需要注意的是不能使用包装类替换基本类型,比如不能使用Integer.class代替int.class
// 调用参数类型 public static void test2() { try { Class cls = Class.forName("com.mimvp.reflect.Student"); Method m1 = cls.getDeclaredMethod("setAge", int.class); // 不能使用Integer.class,否则报错 Method m2 = cls.getDeclaredMethod("getAge"); Object cls2 = cls.newInstance(); int age = (int)m2.invoke(cls2); System.out.println("before Age: " + age); // 0 m1.invoke(cls2, 30); // set 30 age = (int)m2.invoke(cls2); System.out.println("after Age: " + age); // 30 } catch (Exception e) { e.printStackTrace(); } }
4. static 静态方法的反射调用
static方法调用时,不必得到对象示例,如下:
// 调用static静态方法 public static void test3() { try { Class cls = Class.forName("com.mimvp.reflect.Student"); Method m = cls.getDeclaredMethod("hi", String.class, int.class); m.invoke(cls, "mimvp.com", 20); // 20 静态方法hi,不需要newInstance // m.invoke(cls.newInstance(), "mimvp.com", 20); // 20 } catch (Exception e) { e.printStackTrace(); } }
5. private私有成员变量赋值
如果直接通过反射给类的private成员变量赋值,是不允许的,这时我们可以通过setAccessible方法解决。
// private私有成员赋值 public static void test4() { try { Class cls = Class.forName("com.mimvp.reflect.Student"); Object student = cls.newInstance(); Field field = cls.getDeclaredField("age"); field.setAccessible(true); // 设置允许访问 field.set(student, 10); int age = (int)field.get(student); System.out.println("Age: " + age); // 10 } catch (Exception e) { e.printStackTrace(); } }
6. 动态使用get,set方法
在某些场合下,动态使用类中的get,set方法,可以先反射调用set方法,再反射调用get方法达到如上效果
// set / get public static void test5() { try { Class cls = Class.forName("com.mimvp.reflect.Student"); Object student = cls.newInstance(); Method setMethod = cls.getDeclaredMethod("setAge", int.class); setMethod.invoke(student, 100); Method getMethod = cls.getDeclaredMethod("getAge"); int age = (int)getMethod.invoke(student); System.out.println("Age: " + age); // 100 } catch (Exception e) { e.printStackTrace(); } }
反射获取属性
// 获取属性 public static void test6() { try { Class cls = Class.forName("java.lang.Integer"); Field[] fields = cls.getDeclaredFields(); System.out.println("aaa: " + Modifier.toString(cls.getModifiers())); // aaa: public final System.out.println("bbb: " + cls.getSimpleName()); // bbb: Integer // 通过追加的方法,将每个属性拼接到此字符串中 // 最外边的public定义 StringBuffer sb = new StringBuffer(); sb.append(Modifier.toString(cls.getModifiers()) + " class " + cls.getSimpleName() + "{\n"); for(Field field : fields) { 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); } catch (Exception e) { e.printStackTrace(); } }
运行结果:
aaa: public final bbb: Integer public final class Integer{ public static final int MIN_VALUE; public static final int MAX_VALUE; public static final Class TYPE; static final char[] digits; static final char[] DigitTens; static final char[] DigitOnes; static final int[] sizeTable; private final int value; public static final int SIZE; public static final int BYTES; private static final long serialVersionUID; }
参考推荐:
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2017-12-29 02:42:42
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!
这完全是个技术大佬啊!