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 毫秒
*/
}
}
如需转载,请注明文章出处,谢谢!!!
浙公网安备 33010602011771号