反射机制
反射机制指的是在程序运行对类的字节码进行操作,知道类的所有属性和方法;调用方法和属性;调用类的构造方法;获取类的注解;
常用API
1.三种形式获取Class对象
Class clazz = Class.forName("com.juweitu.test.Test01");//根据名称获取
Class clazz1 = Test01.class;
Class clazz2 = new Test01().getClass();
//在同一个虚拟机中运行的类只能有一个class,所以打印结果是一样的
System.out.println(clazz1.hashCode()+","+clazz.hashCode()+","+clazz2.hashCode());
2.四种方式创建实例
2.1 通过Class创建实例
Student stu1 = (Student) clazz.newInstance();
2.2 通过构造方法创建实例
Constructor con[]= clazz.getConstructors();
for(Constructor cons:con){
try {
Student stu1 = (Student)cons.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
2.3 克隆的方式
Student stu2 = (Student)stu.clone();
2.4 序列化和反序列化
Student stu = new Student();
stu.setAge(1);
stu.setName("1");
File file = new File("d:\student.txt");
//序列化过程
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(stu);
//反序列化过程
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
Student stu1 = (Student) ois.readObject();
System.out.println(stu1);
3.常用api
clazz.getDeclaredClasses()返回所有的内部类
getInterfaces()返回所有接口Class数组
getSuperClass()返回父类的Class实例,如果当前类是基本数据类型,或者void,或者Object,就返回null
getModifiers()获得修饰符 返回int 右移加上取模的方式
isMemberClass()是不是内部类
isInterface()是不是接口
isArray()是不是数组
4.属性(java.lang.reflect.Field)
4.1 基本操作
getFields() 获取当前类以及父类里面所有public属性
getField(String fieldName)根据属性名称,获取Field实例。如果获取的属性超出getFields()这个范围,会抛出NoSuchFieldException异常。
getDeclaredFields()获取当前类的所有属性,包含private,protected,缺省的。但不包括其父类或者接口里面的任何属性.
getDeclaredField(String fieldName) 根据属性名称,获取Field实例。如果获取的属性超出getDeclaredFields ()这个范围,会抛出NoSuchFieldException异常。
4.2 注意
在操作私有属性时需要调用这个方法
field.setAccessible(true);//跳过安全检测,并且效率快,不然操作私有属性会抛出SecurityException异常
注意获取属性只能获取本类的属性,下面这个封装可以递归获取父类的属性
private Field getFieldByFieldName(Class clazz,String fieldName){
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
return getFieldByFieldName(clazz,fieldName);
} catch (SecurityException e) {
}
return null;
}
4.3 属性赋值和获取
public void getField() throws IllegalArgumentException, IllegalAccessException{
User user = new User("张三","18");
Field[] fields = User.class.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
field.set(user,"李四");//设置属性值
Object value = field.get(user);//获取属性值
System.out.println(value);
}
}
5.方法(java.lang.reflect.Method)
5.1基本操作
getMethods()能获取本身及其所有父类的public方法。
getMethod (String methodName,Class… paramaterTypes)根据方法和参数列表名称,获取Method实例。如果获取的方法超出getMethods()这个范围,会抛出NoSuchMethodException异常。
getDeclaredMethods()能获取本身所有方法。包含private,protected,缺省的所有方法。但不包括父类的任何方法。
getDeclaredMethod(String fieldName,Class… paramaterTypes)根据方法和参数列表名称,获取Method实例。如果获取的方法超出getDeclaredMethods ()这个范围,会抛出NoSuchMethodException异常。
5.2 调用方法
Class clazz = User.class;
Method method = clazz.getDeclaredMethod("getName", null);//参数名,参数类型,如果无参就传空
Method method2 = clazz.getDeclaredMethod("setName", String.class);
method2.setAccessible(true);
//调用方法
method2.invoke(clazz.newInstance(),"张三");//类的实例,参数值
6.构造方法 (java.lang.reflect.Constructor)
6.1 基本操作
getConstructors() 能取得所有public的构造方法
getDeclaredConstructors() 能取得所有的构造方法,包含private,protected,缺省的。
newInstance(paramaterTypes)调用相应的public构造方法,生成实例
如果要访问private的构造方法,设置constructor.setAccessable(true)来解决。
6.2 构成方法赋值
Constructor constructor = User.class.getDeclaredConstructor(String.class,String.class);
constructor.setAccessible(true);
User user = constructor.newInstance("张三","18");
7.调用静态方法
//调用静态的方法
Method method = User.class.getMethod("test",String.class);
method.invoke(null,"张三");//静态方法不需要实例
//调用静态属性
Field field = User.class.getField("WIDTH");
Object width = field.get(null);//不需要实例
field.set(null, 600);
System.out.println(width+","+field.get(null));
8.性能测试
User user = new User();
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
user.setName("张三");
}
long end = System.currentTimeMillis();
System.out.println("普通调用耗时"+(end-start)+"毫秒");
Class clazz = User.class;
start = System.currentTimeMillis();
Field field = null;
for (int i = 0; i < 1000000; i++) {
field = clazz.getField("name");
field.set(user, "张三");
}
end = System.currentTimeMillis();
System.out.println("反射调用,没有跳过安全检测耗时"+(end-start)+"毫秒");
start = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
field = clazz.getField("name");
field.setAccessible(true);
field.set(user, "张三");
}
end = System.currentTimeMillis();
System.out.println("反射调用,跳过安全检测耗时"+(end-start)+"毫秒");
9.操作泛型(java.lang.reflect.Type)
9.1基本操作
ParameterizedType 表示参数化类型,如 Collection。
GenericArrayType 表示一种数组类型,其组件类型为参数化类型或类型变量。
TypeVariable 是各种类型变量的公共高级接口。
WildcardType 表示一个通配符类型表达式,如 ?、? extends Number 或 ? super Integer。
9.2 获取方法上的注解
public void test01(Map map,List list) {
System.out.println("test01");
}
public Map test02() {
System.out.println("test02");
return null;
}
public void getType() throws Exception{
System.out.println("------获取方法参数的泛型-------");
Class clazz = this.getClass();
Method method = clazz.getMethod("test01", Map.class,List.class);
Type[] types = method.getGenericParameterTypes();//获取方法参数的泛型
for (Type paramType : types) {
System.out.println("#"+paramType);
if (paramType instanceof ParameterizedType) {
Type[] typeArguments = ((ParameterizedType)paramType).getActualTypeArguments();
for (Type typeArgument : typeArguments) {
System.out.println(typeArgument);//获取具体的泛型
}
}
}
System.out.println("------获取方法返回的泛型-------");
Method method2 = clazz.getMethod("test02",null);
Type returnType = method2.getGenericReturnType();//获取方法返回的泛型
if (returnType instanceof ParameterizedType) {
Type[] typeArguments = ((ParameterizedType)returnType).getActualTypeArguments();
System.out.println("#"+returnType);
for (Type typeArgument : typeArguments) {
System.out.println(typeArgument);//获取具体的泛型
}
}
}
9.3 获取当前类上泛型的类型(针对Hibernate)
只要XxxDao继承了BaseDao那么增删改查一个都不需要写。
public class BaseDao {
//获取
public T get(Serializable id){
Session session = SessionFactoryUtil.getSessionFactory().openSession();
session.getTransaction().begin();
T obj = (T) session.get(getModleClass(), id);
session.getTransaction().commit();
session.close();
return obj;
}
//增加
//删除
//修改
public Class getModleClass(){
//获取当前的T的类型
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
Class clazz = (Class) pt.getActualTypeArguments()[0] ;
return clazz;
}
}
public class StudentDao extends BaseDao {
}