Java 反射Reflection
目录
Class对象
我们以前在使用new关键字来创建对象的时候,JVM会首先将该class加载,保存的是一个模子,之后使用new关键字来创建的对象保证都是一样的。这个模子保存了class的所有信息(结构和属性)。
但是有时候,我们在工作中,需要实例化的类有时候是未知的(不同的情况需要实例化不同的类),此时,我们希望能动态的传入类的名字,然后在实例化这个类,而不是将类名写死。
一个类型只对应一个Class对象
package lixin.gan.note; public class Reflection01 { public static void main(String[] args) { try { String path = "lixin.gan.orm.annotation.Person"; Class clas1 = Class.forName(path); Class clas2 = Class.forName(path); System.out.println(clas1.hashCode() == clas2.hashCode()); // true // 说明上面的两个类是一个Class对象 // 注意,类型相同,则对应的Class对象相同,对于数组而言,与数组的元素类型和维数相关,与长度无关 int[] a1 = new int[10]; int[] a2 = new int[20]; int[][] a3 = new int[10][20]; System.out.println(a1.getClass().hashCode() == a2.getClass().hashCode()); // true System.out.println(a1.getClass().hashCode() == a3.getClass().hashCode()); // false double[] d4 = new double[10]; System.out.println(d4.getClass().hashCode() == a1.getClass().hashCode()); // false } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
获得Class对象的三种方法
package lixin.gan.basic; import java.lang.reflect.InvocationTargetException; class Person{ private int id; private String name; public Person() { super(); } public Person(int id, String name) { super(); this.id = id; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + "]"; } } public class GetClassObject { public static void main(String[] args) { /** * 方式1, 通过对象来获取 */ Person p = new Person(); Class personClass = p.getClass(); /** * 方式2, 使用类名 */ personClass = Person.class; /** * 方式3, 使用类的包名 + 类名 */ try { personClass = Class.forName("lixin.gan.basic.Person"); // 无参构造 // Person p2 = (Person)personClass.getConstructor().newInstance(); // 有参构造 Person p2 = (Person)personClass.getConstructor(int.class, String.class).newInstance(1, "abc"); System.out.println(p2); } catch (Exception e) { e.printStackTrace(); } } }
利用反射获取类的相关信息
package lixin.gan.test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 利用反射,获取类的相关信息(类名、属性、方法、注解、构造器) */ public class GetClassObjectInfo { /** * 获取类的名字 */ public static void getClassName() { try { String path = "lixin.gan.orm.annotation.Person"; Class clas = Class.forName(path); // 获得完整路径 + 类名 System.out.println(clas.getName()); // lixin.gan.orm.annotation.Person // 获得类名 System.out.println(clas.getSimpleName()); // Person } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 获取属性信息 */ public static void getFieldInfo() { try { String path = "lixin.gan.orm.annotation.Person"; Class clas = Class.forName(path); /* * 获取所有的public属性 Field[] fields = clas.getFields(); for (Field f : fields) { System.out.println(f); } */ /* * 获取所有的属性(包括private) Field[] fields = clas.getDeclaredFields(); for (Field field : fields) { System.out.println(field); // 默认打印属性的所有信息 // private int lixin.gan.orm.annotation.Person.id System.out.println(field.getName()); // 只简单打印属性的名称 // id } */ // 获取指定名称的属性 Field field = clas.getDeclaredField("name"); System.out.println(field + "--" + field.getName()); // private java.lang.String lixin.gan.orm.annotation.Person.name--name } catch (Exception e) { e.printStackTrace(); } } /** * 获取对象的方法 */ public static void getMethodInfo() { try { String path = "lixin.gan.orm.annotation.Person"; Class clas = Class.forName(path); /* * 获取所有public的方法,注意,包含很多从父类中继承而来的public方法 Method[] methods = clas.getMethods(); for(Method method : methods) { System.out.println(method); } */ /* * 获取所有public的方法 * 注意,只返回自己定义的方法,不会包含从父类中继承而来的public方法 Method[] methods = clas.getDeclaredMethods(); for(Method method : methods) { System.out.println(method); } */ // 获取指定的方法名称,需要指定方法的参数类型,因为可能会出现重载的多个同名方法 Method method = clas.getDeclaredMethod("setName", String.class); System.out.println(method); // public void lixin.gan.orm.annotation.Person.setName(java.lang.String) } catch (Exception e) { e.printStackTrace(); } } /** * 获取构造器的信息 */ public static void getConstructorInfo() { try { String path = "lixin.gan.orm.annotation.Person"; Class clas = Class.forName(path); // 获取所有public的构造器 //Constructor[] constructors = clas.getConstructors(); // 获取所有的构造器 Constructor[] constructors = clas.getDeclaredConstructors(); // 获取指定的构造器,需要传入参数,因为构造器可能会重载,不传入参数,表示无参构造器 Constructor constructor = clas.getDeclaredConstructor(int.class, String.class, String.class); } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { getConstructorInfo(); } }
利用反射来调用构造器、属性、普通方法
package lixin.gan.test; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import lixin.gan.annotation.MyField; import lixin.gan.annotation.MyTable; import lixin.gan.annotation.Person; /** * 通过反射,动态使用构造器、方法、属性、注解 */ public class ReflectionToUse { /** * 利用反射来实例化对象 */ public static void getInstance() { try { String path = "lixin.gan.orm.annotation.Person"; /*使用泛型 Class<Person> clas =(Class<Person>)Class.forName(path); Person p = clas.newInstance(); // 调用无参构造方法 System.out.println(p); // Person [id=0, name=null, gender=null] */ /* 使用强制类型转换 Class clas = Class.forName(path); Person p = (Person)clas.newInstance(); System.out.println(p); */ /*通过选定构造器来获取对象实例*/ Class clas = Class.forName(path); Constructor<Person> constructor = clas.getConstructor(int.class, String.class, String.class); Person p = constructor.newInstance(100, "ganlixin", "male"); System.out.println(p); // Person [id=100, name=ganlixin, gender=male] // 一步完成可以写成 p = (Person) clas.getConstructor(int.class, String.class, String.class).newInstance(1001, "xyz", "male"); System.out.println(p); // Person [id=1001, name=xyz, gender=male] // 注意上面用得是getConstructor,也可以使用getDeclaredConstructor,毕竟,能够调用,应该就是public的 } catch (Exception e) { e.printStackTrace(); } } /** * 利用反射来调用普通方法 */ public static void callSimpleMethod() { String path = "lixin.gan.orm.annotation.Person"; try { Class clas = Class.forName(path); Constructor<Person> constructor = clas.getDeclaredConstructor(int.class, String.class, String.class); Person person = constructor.newInstance(100, "xyz", "male"); System.out.println(person); // 获取要调用的方法,注意传入参数列表的类型,因为可能出现重载 Method method = clas.getDeclaredMethod("setName", String.class); // method.invode(obj, args); 调用obj对象的method方法,参数是args method.invoke(person, "abc"); System.out.println(person); // Person [id=100, name=abc, gender=male] } catch (Exception e) { e.printStackTrace(); } } /** * 操作属性 */ public static void manageField() { String path = "lixin.gan.orm.annotation.Person"; try { Class clas = Class.forName(path); Constructor<Person> constructor = clas.getDeclaredConstructor(int.class, String.class, String.class); Person person = constructor.newInstance(100, "xyz", "male"); System.out.println(person); // 直接通过getter或者setter来 获取、设置属性值 person.getName(); Field field = clas.getDeclaredField("name"); /* * // 直接设置或者访问属性值,如果没有访问权限,就会出错 * field.get(person) * field.set(person, "aaaa"); */ // 正确方式,应该先设置为可获取 field.setAccessible(true); System.out.println(field.get(person)); // xyz field.set(person, "aaa"); System.out.println(person); // Person [id=100, name=aaa, gender=male] /** * field.get(obj) 表示获取obj对象的field属性 * field.set(obj, value) 表示设置obj的field属性值 */ } catch (Exception e) { e.printStackTrace(); } } /** * 获取注解的相关信息 */ public static void getAnnotationsInfo() { String path = "lixin.gan.orm.annotation.Person"; try { Class clas = Class.forName(path); Person p = (Person)clas.getConstructor(int.class, String.class, String.class).newInstance(100, "hello", "male"); // 获得类的所有注解,注意是类的,而不是属性的 Annotation[] annotations = clas.getDeclaredAnnotations(); for (Annotation a : annotations) { System.out.println(a); } /* @lixin.gan.orm.annotation.MyTable(value=Person) @lixin.gan.orm.annotation.MyAnnotation2(value=hehe) */ // 获得类的指定注解 // 假设我已经知道该类有哪些注解,我现在想知道其中一个注解的相关信息, Annotation annotation = clas.getDeclaredAnnotation(MyTable.class); System.out.println(annotation); // @lixin.gan.orm.annotation.MyTable(value=person) System.out.println(((MyTable)annotation).value()); // person // 也可以这样 MyTable myTableAnnotation = (MyTable) clas.getDeclaredAnnotation(MyTable.class); System.out.println(myTableAnnotation); // @lixin.gan.orm.annotation.MyTable(value=person) System.out.println(myTableAnnotation.value()); // person // 获得属性的注解, 和获得类的注解是一样的 // 注意,需要先获得属性,然后通过属性来获取注解 Field field = clas.getDeclaredField("name"); MyField myFieldAnnotation = field.getDeclaredAnnotation(MyField.class); System.out.println(myFieldAnnotation); // @lixin.gan.orm.annotation.MyField(canEmpty=true, primaryKey=false, columnName=name, type=varchar, length=30) System.out.println(myFieldAnnotation.columnName() + "--" + myFieldAnnotation.type() + "--" + myFieldAnnotation.length()); // name--varchar--30 } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { getAnnotationsInfo(); } }
低效的反射--关闭安全检查
为了提高反射的效率,可以通过setAccessible(true)来关闭权限检测。
package lixin.gan.test; import java.lang.reflect.Method; /** * 测试效率 */ class Person { private String name; public Person(String name) { this.name = name; } public String getName() { return name; } } public class TestEfficiency{ /** * 使用最原始的方式来调用方法 */ public static void test1() { Person person = new Person("Jane"); for (int i = 0; i < 100000000L; i++) { person.getName(); } } /** * 使用反射的方式来调用方法,并且每次都要进行权限检查(private、protected、public、default) */ public static void test2() { try { Class clas = Class.forName("lixin.gan.note.Person"); Person person = (Person)clas.getConstructor(String.class).newInstance("Jane"); Method method = clas.getDeclaredMethod("getName", null); // 通常,在调用一个方法的时候,我们会先检查权限问题,比如private的权限,不能在外部访问或调用。 // 所以下面的1亿次的调用,就会进行1亿次权限检查 for (int i = 0; i < 100000000L; i++) { method.invoke(person, null); } } catch (Exception e) { e.printStackTrace(); } } /** * 同样使用反射的方式调用方法,只不过在调用之前,关闭权限检查,这样的话,不用每次调用方法都进行权限检查了 */ public static void test3() { try { Class clas = Class.forName("lixin.gan.note.Person"); Person person = (Person)clas.getConstructor(String.class).newInstance("Jane"); Method method = clas.getDeclaredMethod("getName", null); method.setAccessible(true); // 通常,在调用一个方法的时候,我们会先检查权限问题,比如private的权限,不能在外部访问或调用。 // 通过这一步设置后,之后调用这个方法,就不会进行权限检查了,即使他是private,也是可以调用的 for (int i = 0; i < 100000000L; i++) { method.invoke(person, null); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { long start, end; start = System.currentTimeMillis(); test1(); end = System.currentTimeMillis(); System.out.println("test1 耗费了 " + (end-start) + " 毫秒"); start = System.currentTimeMillis(); test2(); end = System.currentTimeMillis(); System.out.println("test2 耗费了 " + (end-start) + " 毫秒"); start = System.currentTimeMillis(); test3(); end = System.currentTimeMillis(); System.out.println("test3 耗费了 " + (end-start) + " 毫秒"); /* 统计数据如下: test1 147毫秒 148 毫秒 147 毫秒 test2 1043 毫秒 938 毫秒 936 毫秒 test3 477 毫秒 469 毫秒 470 毫秒 */ } }
如需转载,请注明文章出处,谢谢!!!