这篇文章讲述的是java中的反射机制,如有错误或不当之处,还望各位大神批评指正。
什么是反射机制?
- 当程序运行时可以加载一个只有名称的类,对于一个已经加载的类都可以知道这个类的所有属性和方法,对于一个已经加载的对象,都可以调用这个对象的任意一个方法和任意属性。
- 是指可以运行时加载、探知、使用编译期间完全未知的类。
通过Class加载类
java.Lang.Class用于表示一个运行时类,方式如下:
- 通过Class.forName获取
- 通过XXX.class获取
- 通过路径.class获取
例:
//加载一个运行时类
//方式一:通过类的全路径获取
Class<Student> clazz = (Class<Student>) Class.forName("com.cn.cmc.reflection.Student") ;
System.out.println(clazz);
//方式二:通过类.class获取
Class<Student> clazz2 = Student.class ;
System.out.println(clazz2);
//方式三://通过类路径.class获取
Class<Student> clazz3 = com.cn.cmc.reflection.Student.class ;
System.out.println(clazz3);
注:运行时类只能加载一次
操作Class类
- 通过Class加载类之后可以对类进行动态操作,主要操作有:
- 动态获取类的信息(属性、构造器、方法)
- 动态构造对象
- 调用类和对象的任意的方法和构造器
- 动态调用和处理属性
- 获取泛型信息
- 处理注解
获取类的信息(名字、属性、方法、构造器)
获取名字
/*名字*/
//获取类的全类名
System.out.println(clazz.getName());
//获取类名
System.out.println(clazz.getSimpleName());
获取属性
/*属性*/
//获取某个public的属性(非共有的不访问)
System.out.println(clazz.getField("name"));
//获取某个属性(访问非公有)
System.out.println(clazz.getDeclaredField("name"));
//获取所有public属性(非公有不访问)
Field []f = clazz.getFields() ;
for(Field temp : f){
System.out.println(temp);
}
//获取所有属性(访问非公有)
Field []f2 = clazz.getDeclaredFields() ;
for(Field temp : f2){
System.out.println(temp);
}
获取方法
/*获取方法*/
//通过名称和参数类型获取方法(不包括私有方法)
Method m1 = clazz.getMethod("show", null) ;
//通过名称和参数类型获取方法(包括私有方法)
Method m2 = clazz.getDeclaredMethod("show", null) ;
//获取所有方法(不包括私有且包括所有父类方法)
Method [] methods1 = clazz.getMethods() ;
for(Method m : methods1){
System.out.println(m);
}
//获取所有方法(包括私有且不包括父类方法)
Method [] methods2 = clazz.getDeclaredMethods() ;
for(Method m : methods2){
System.out.println(m);
}
获取构造器
/*获取构造器*/
//获取公有构造器
Constructor c1 = clazz.getConstructor(Integer.class, String.class, char.class, int.class) ;
System.out.println(c1);
//获取所有公有构造器
Constructor []cs1 = clazz.getConstructors() ;
for(Constructor c : cs1){
System.out.println(c);
}
//获取构造器(包括私有)
Constructor c2 = clazz.getDeclaredConstructor(Integer.class, String.class, char.class, int.class) ;
System.out.println(c2);
//获取所有构造器(包括私有)
Constructor []cs2 = clazz.getDeclaredConstructors() ;
for(Constructor c : cs2){
System.out.println(c);
}
新建对象
/*新建对象*/
//通过无参构造器
Student s = clazz.newInstance() ;
System.out.println(s);
//通过制定构造器
Constructor<Student> constructor = clazz.getConstructor(Integer.class,String.class,char.class,int.class) ;
Student s2 = constructor.newInstance(100001,"叶清逸",'M',25) ;
System.out.println(s2);
调用任意对象的方法
//调用普通方法
Method m = clazz.getMethod("setName", String.class) ;
m.invoke(s, "叶清逸");
System.out.println(s);
调用和处理属性
//操作属性
Field f = clazz.getDeclaredField("name") ;
f.setAccessible(true);//跳过private的安全检查
f.set(s, "叶清逸");
System.out.println(f.get(s));
注:若没有f.setAccessible(true);则不可访问私有属性
反射的性能问题
若使用反射机制则会带来性能的问题,执行速度比较慢,这时需要将setAccessible的值设置为true。
例:
package com.cn.cmc.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class test {
/**
* 反射机制
*/
public static void main(String[] args) throws Exception{
//加载一个运行时类
test1() ;
test2() ;
test3() ;
}
public static void test1(){
Student s = new Student() ;
Long start = System.currentTimeMillis();
for(int i=0 ; i<1000000000L ; i++){
s.getName() ;
}
Long end = System.currentTimeMillis();
System.out.println("普通调用耗时:"+(end-start));
}
public static void test2() throws Exception{
Class<Student> clazz = Student.class ;
Method m = clazz.getDeclaredMethod("getName") ;
Student s = clazz.newInstance() ;
Long start = System.currentTimeMillis();
for(int i=0 ; i<1000000000L ; i++){
m.invoke(s);
}
Long end = System.currentTimeMillis();
System.out.println("反射调用,使用安全检查耗时:"+(end-start));
}
public static void test3()throws Exception{
Class<Student> clazz = Student.class ;
Method m = clazz.getDeclaredMethod("getName") ;
Student s = clazz.newInstance() ;
m.setAccessible(true);
Long start = System.currentTimeMillis();
for(int i=0 ; i<1000000000L ; i++){
m.invoke(s);
}
Long end = System.currentTimeMillis();
System.out.println("反射调用,跳过安全检查耗时:"+(end-start));
}
}