Java反射详解

反射机制

反射机制指的是在程序运行对类的字节码进行操作,知道类的所有属性和方法;调用方法和属性;调用类的构造方法;获取类的注解;

常用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);
 
    }
 
}

image-20210525170100529

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));

image-20210525170258582

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)+"毫秒");

image-20210525170319602

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);//获取具体的泛型
 
        }
 
    }
 
}

image-20210525170340021

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 {
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

terrybg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值