反射:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。也就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。
获取class文件对象的方式:
Reflect01.java
public class Reflect01 { public static void main(String[] args) throws Exception { // 方式一 Person p1 = new Person(); Class c1 = p1.getClass(); Person p2 = new Person(); Class c2 = p2.getClass(); System.out.println(p1 == p2); // false System.out.println(c1 == c2); // true // 方式二 Class c3 = Person.class; System.out.println(c1 == c3); // true // 方式三 Class c4 = Class.forName("bean.Person"); System.out.println(c1 == c4); // true } }
person.java
public class Person { private String name; int age; public String address; public Person() { } private Person(String name) { this.name = name; } Person(String name, int age) { this.name = name; this.age = age; } public Person(String name, int age, String address) { this.name = name; this.age = age; this.address = address; } public void show() { System.out.println("show"); } public void method(String s) { System.out.println("method " + s); } public String getString(String s, int i) { return s + "---" + i; } private void function() { System.out.println("function"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", address=" + address + "]"; } }
三种方法中,最常用第三种。因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。
通过反射获取构造方法
public class Reflect02 { public static void main(String[] args) throws Exception { // 获取字节码文件 Class<?> c = Class.forName("bean.Person"); // 获取多个构造方法 // Constructor[] cons = c.getConstructors(); 获取公共的构造方法 // Constructor[] cons = c.getDeclaredConstructors(); 获取所有的构造方法 // 获取单个无参构造方法 Constructor<?> con = c.getConstructor(); Object obj = con.newInstance(); System.out.println(obj); } }
通过反射获取带参构造方法
第一种情况
public class Reflect03 { public static void main(String[] args) throws Exception { // 获取字节码文件对象 Class c = Class.forName("cn.itcast_01.Person"); // 获取带参构造方法对象 // public Constructor<T> getConstructor(Class<?>... parameterTypes) Constructor con = c.getConstructor(String.class, int.class, String.class); // 通过带参构造方法对象创建对象 // public T newInstance(Object... initargs) Object obj = con.newInstance("林青霞", 27, "北京"); System.out.println(obj); } }
这种情况运行顺利通过
但是下面就报错
public class Reflect03 { public static void main(String[] args) throws Exception { // 获取字节码文件 Class<?> c = Class.forName("bean.Person"); // 获取单个带参构造方法 Constructor<?> con = c.getDeclaredConstructor(String.class, int.class); Object obj = con.newInstance("susu",12); System.out.println(obj); } }
错误信息
Exception in thread "main" java.lang.IllegalAccessException: Class 反射使用.Reflect03 can not access a member of class bean.Person with modifiers "" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102) at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296) at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288) at java.lang.reflect.Constructor.newInstance(Constructor.java:413) at 反射使用.Reflect03.main(Reflect03.java:16)
此时我们需要加上一句话
con.setAccessible(true); // 值为true则指示反射的对象在使用时应该取消Java语言访问检查。此时运行就通过了。
通过反射获取成员变量
public class Reflect04 { public static void main(String[] args) throws Exception { // 获取字节码文件 Class<?> c = Class.forName("bean.Person"); // 通过无参构造获取对象 Constructor<?> con = c.getConstructor(); Object obj = con.newInstance(); // 获取单个成员变量 // 获取address并赋值 Field addressField = c.getDeclaredField("address"); // 给obj对象的addressField字段设置为北京,实际就是给address赋值 addressField.set(obj, "西安"); // 获取name并赋值 Field nameField = c.getDeclaredField("name"); // 由于name是私有属性,因此取消Java语言访问检查。 nameField.setAccessible(true); nameField.set(obj, "susu"); // 获取age并赋值 Field ageField = c.getDeclaredField("age"); ageField.setAccessible(true); ageField.set(obj, 22); System.out.println(obj); } }
通过反射获取成员方法
public class Reflect05 { public static void main(String[] args) throws Exception { // 获取字节码文件 Class<?> c = Class.forName("bean.Person"); // 获取所有方法 // Method[] methods = c.getMethods(); // 获取自己的和父类的方法 // Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法 // for (Method method : methods) { // System.out.println(method); // } Constructor<?> con = c.getConstructor(); Object obj = con.newInstance(); // 获取单个方法使用,不带返回值 // public Method getMethod(String name,Class<?>... parameterTypes) // 第一个参数表示方法名,第二个参数表示的是方法的参数的class类型 Method m1 = c.getMethod("show"); // public Object invoke(Object obj,Object... args) // 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数 m1.invoke(obj); Method m2 = c.getMethod("method", String.class); m2.invoke(obj, "hello"); // 获取单个方法使用,带返回值 Method m3 = c.getMethod("getString", String.class, int.class); Object object = m3.invoke(obj, "su", 22); System.out.println(object); // 获取单个私有方法使用 Method m4 = c.getDeclaredMethod("function"); m4.setAccessible(true); m4.invoke(obj); } }