初识反射
通过反射可以获取类的Class对象, 一个类在内存中只有一个Class对象,Class对象不能开发者自己创建, 只能获取, 一个类被加载后类的整个结构都将被封装在Class对象中
获得Class对象的几种方法
public class GetClass {
public static void main(String[] args) throws ClassNotFoundException {
//1.通过 对象.getClass() 获得
Teacher william = new Teacher("william");
Class c1 = william.getClass();
System.out.println(c1);
System.out.println("c1.hashCode() = " + c1.hashCode());
//2.Class.forName(String className) 获得
Class c2 = Class.forName("com.cqu.william.AnnotationAndReflection.Student");
System.out.println("c2.hashCode() = " + c2.hashCode());
//3.通过 类名.class 获得
Class c3 = Student.class;
System.out.println(c3);
System.out.println("c3.hashCode() = " + c3.hashCode()); //同一个类的Class的hashcode相同
//4.基本内置类型的包装类都有一个TYPE属性
Class<Integer> c4 = Integer.TYPE;
System.out.println("c4 = " + c4);
//5.通过Class.getSuperclass()可以获得其父类的Class对象
Class c5 = c2.getSuperclass();
System.out.println("c5 = " + c5);
}
}
class Person {
public String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
}
class Student extends Person {
public Student(String name) {
super(name);
}
}
class Teacher extends Person {
public Teacher(String name) {
super(name);
}
}
Class.getxxx()
public class GetName {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.cqu.william.AnnotationAndReflection.User");
//获得类的名字
System.out.println("c1.getName() = " + c1.getName());//获得包名+类名
System.out.println("c1.getSimpleName() = " + c1.getSimpleName());//获得类名
//获得类的属性
Field[] fields = c1.getFields(); //只能获得public属性的数组
for (Field field : fields) {
System.out.println(field);
}
System.out.println("======================================");
fields = c1.getDeclaredFields(); //获得所有属性的数组
for (Field field : fields) {
System.out.println(field);
}
System.out.println("======================================");
Field name = c1.getDeclaredField("name");
System.out.println(name);//获得指定属性
System.out.println("======================================");
// 获得方法
Method[] methods = c1.getMethods();//获得本类及父类的所有public方法的数组
for (Method method : methods) {
System.out.println(method);
}
System.out.println("======================================");
Field[] declaredFields = c1.getDeclaredFields();//获得本类的所有方法的数组
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("======================================");
//获得所有public构造器的数组
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("======================================");
//获得所有public构造器的数组
Constructor[] declaredConstructors = c1.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
}
}
动态创造对象
public class Dyn {
private static Object william;
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class c1 = Class.forName("com.cqu.william.AnnotationAndReflection.User");
//使用newInstance()动态构造对象
User user = (User) c1.newInstance();
System.out.println(user);
//使用getDeclaredConstructor(params)获取构造器, 通过构造器创建对象
Constructor c = c1.getDeclaredConstructor(String.class, int.class, int.class);
Object william = c.newInstance("william", 20193818, 19);
//使用getDeclaredMethod()获取指定方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//使用invoke调用william对象的setName方法,参数为"ABC"
setName.invoke(william, "ABC");
//使用getDeclaredField()获得字段
Field name = c1.getDeclaredField("name");
//setAccessible(true)关闭反射的检测
name.setAccessible(true);
name.set(william, "william");
}
}
反射的执行表现
反射使得执行效率大大降低, 通过关闭检测setAccessible(true)能稍微提升
// 分别使用三种方式执行10亿次循环, 记录所用的时间, 比较执行效率
public class Performance {
public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
test01();
test02();
test03();
}
//普通方式调用getName()
static void test01() {
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方式执行循环体10亿次 " + (endTime - startTime) + "ms");
}
//反射方式调用getName()
static void test02() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
User user = new User();
//通过getClass()得到user的Class对象
Class c1 = user.getClass();
// getDeclaredMethod("getName")得到User.getName()方法
Method getName = c1.getDeclaredMethod("getName");
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
// getName.invoke(user)表示对user对象使用getName方法
getName.invoke(user);
}
long endTime = System.currentTimeMillis();
System.out.println("反射方式执行循环体10亿次 " + (endTime - startTime) + "ms");
}
//反射方式调用getName()并关闭检测
static void test03() throws NoSuchMethodException {
User user = new User();
Class c3 = user.getClass();
Method getName = c3.getDeclaredMethod("getName");
//setAccessible(true)关闭检测
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("关闭检测执行循环体10亿次 " + (endTime - startTime) + "ms");
}
}