Java反射详解

1.三种形式获取Class对象

Class<?>clazz = Class.forName("com.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创建实例
Studentstu1 = (Student)clazz.newInstance();

2.2 通过构造方法创建实例
Constructor con[]=clazz.getConstructors();
for(Constructor cons:con){
try {
Student stu1 = (Student)cons.newInstance();
} catch (Exceptione) {
e.printStackTrace();
}
}

2.3 克隆的方式
Student stu2 =Studentstu.clone(); 

2.4 序列化和反序列化
Studentstu =new Student();
stu.setAge(1);
stu.setName("1");
Filefile =new File("d:\\student.txt");
//序列化过程
FileOutputStreamfos =new FileOutputStream(file);
ObjectOutputStreamoos =new ObjectOutputStream(fos);
oos.writeObject(stu);
//反序列化过程
FileInputStreamfis =new FileInputStream(file);
ObjectInputStreamois =new ObjectInputStream(fis);
Studentstu1 = (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 FieldgetFieldByFieldName(Class<?>clazz,StringfieldName){
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldExceptione) {
return getFieldByFieldName(clazz,fieldName);
} catch (SecurityExceptione) {
}
return null;
}

4.3 属性赋值和获取
public void getField()throws IllegalArgumentException, IllegalAccessException{
User user =new User("张三","18");
Field[] fields = User.class.getDeclaredFields();
for (Fieldfield :fields) {
field.setAccessible(true);
field.set(user,"李四");//设置属性值
Object value =field.get(user);//获取属性值
System.out.println(value);
}
}

Java反射详解



5.方法(java.lang.reflect.Method)

5.1基本操作
getMethods()能获取本身及其所有父类的public方法。
getMethod (StringmethodName,Class paramaterTypes)根据方法和参数列表名称,获取Method实例。如果获取的方法超出getMethods()这个范围,会抛出NoSuchMethodException异常。
 
getDeclaredMethods()能获取本身所有方法。包含private,protected,缺省的所有方法。但不包括父类的任何方法。
getDeclaredMethod(String fieldName,Class paramaterTypes)根据方法和参数列表名称,获取Method实例。如果获取的方法超出getDeclaredMethods ()这个范围,会抛出NoSuchMethodException异常。

5.2 调用方法
Class<?>clazz = User.class;
Methodmethod =clazz.getDeclaredMethod("getName",null);//参数名,参数类型,如果无参就传空
Methodmethod2 =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<User>constructor = User.class.getDeclaredConstructor(String.class,String.class);
constructor.setAccessible(true);
Useruser =constructor.newInstance("张三","18");

7.调用静态方法
//调用静态的方法
Methodmethod = User.class.getMethod("test",String.class);
method.invoke(null,"张三");//静态方法不需要实例
//调用静态属性
Fieldfield = User.class.getField("WIDTH");
Objectwidth =field.get(null);//不需要实例
field.set(null, 600);
System.out.println(width+","+field.get(null));
Java反射详解

8.性能测试
Useruser =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();
Fieldfield =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)+"毫秒");
Java反射详解

9.操作泛型(java.lang.reflect.Type)

9.1基本操作
ParameterizedType 表示参数化类型,如 Collection<String>。
GenericArrayType 表示一种数组类型,其组件类型为参数化类型或类型变量。
TypeVariable 是各种类型变量的公共高级接口。
WildcardType 表示一个通配符类型表达式,如?? extends Number? super Integer

9.2 获取方法上的注解
public void test01(Map<String,Integer>map,List<String>list) {
System.out.println("test01");
}
public Map<String,Integer> 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 (TypeparamType :types) {
System.out.println("#"+paramType);
if (paramType instanceof ParameterizedType) {
Type[] typeArguments = ((ParameterizedType)paramType).getActualTypeArguments();
for (TypetypeArgument :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 (TypetypeArgument :typeArguments) {
System.out.println(typeArgument);//获取具体的泛型
}
}
}
Java反射详解
9.3 获取当前类上泛型的类型(针对Hibernate)
只要XxxDao继承了BaseDao那么增删改查一个都不需要写。
public class BaseDao<T> {
//获取
public T get(Serializableid){
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<T> clazz =(Class<T>)pt.getActualTypeArguments()[0] ;
return clazz;
}
}
public class StudentDaoextends BaseDao<StudentBean> {
}