反射与注解

本文详细介绍了Java中的反射机制,包括如何通过反射创建对象、调用构造器、方法和属性,以及如何使用setAccessible提高反射效率。同时,文章探讨了反射与注解的性能差异,通过实例展示了获取泛型信息的方法。最后,文章通过示例展示了如何通过反射获取类和属性上的注解信息,这对于理解ORM框架的工作原理非常重要。
摘要由CSDN通过智能技术生成

反射与注解

通过反射操作对象

User类

public class User {
    private String name;
    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    private void test(){ }
}
  • 创建类的对象:调用Class对象的newInstance()方法
    • 类必须有一个无参数的构造器
    • 类的构造器的访问权限需要足够
//获取Class对象
Class c1 = Class.forName("com.yjj.reflection.User");

//构造一个对象
User user = (User)c1.newInstance();//调用无参
System.out.println(user);

结果:

User{name='null', age=0}
  • 调用有参构造
    • 通过getDeclaredConstructor传入指定形参类型调用指定构造器
    • 然后通过构造器的newInstance()方法传具体的值,实例化对象
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class);
User user2 = (User) constructor.newInstance("yjj", 18);
System.out.println(user2);

结果:

User{name='yjj', age=18}
  • 调用指定方法
    • 通过getMethod或getDeclaredMethod方法,传入方法名,方法参数,调用指定方法
    • 然后通过invoke方法激活,传入对象和方法需要的值
//通过反射调用普通方法
User user3 = (User) c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod("setName",String.class);

//invoke:激活
//invoke(对象,"方法的值")
setName.invoke(user3,"yjj");
System.out.println(user3.getName());
  • 注意:
    • invoke对应的原方法无返回值时,写null,有返回值要传
    • 如果为私有的方法,需要调用setAccessible(true),设置可访问性

setAccessible

  • 方法、属性、构造器对象都有setAccessible()方法
  • setAccessible:设置可访问性,作用是启动和禁用访问安全检查的开关
  • 默认时false,即不可访问私有。设置true可取消Java语言访问检查
  • 在反射中设置true,可提高反射的效率,使得原本私有成员也可被访问
//通过反射操作属性
User user4 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");

//私有属性不能直接访问,所以要设置可访问性,Accessible默认开启
name.setAccessible(true);//安全性降低
name.set(user4,"yjj2");
System.out.println(user4.getName());

性能对比

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test09 {
    public static void test01(){
        User user = new User();
        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 1000000; i++) {
            user.getName();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("普通方法执行10亿次:"+(endTime-startTime)+"ms");
    }
    public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();

        Method getName = c1.getMethod("getName", null);

        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 1000000; i++) {
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("反射方法执行10亿次:"+(endTime-startTime)+"ms");
    }

    public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();

        Method getName = c1.getMethod("getName", null);
        getName.setAccessible(true);
        long startTime = System.currentTimeMillis();

        for (int i = 0; i < 1000000; i++) {
            getName.invoke(user,null);
        }
        long endTime = System.currentTimeMillis();
        System.out.println("关闭检测执行10亿次:"+(endTime-startTime)+"ms");
    }

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test01();
        test02();
        test03();
    }
}

结果:

普通方法执行10亿次:3ms
反射方法执行10亿次:10ms
关闭检测执行10亿次:5ms

  • 可见效率普通方法>关闭检测的反射>反射
  • 虽然关闭检查的反射效率高于反射,但是安全性降低

获取泛型信息

  • 先获取方法
  • 通过方法获取它的泛型参数化类型(getGenericParameterTypes())或者返回值泛型(getGenericReturnType())
  • 判断是否时参数化类型(ParameterizedType),是就强转,然后通过获得真实参数的方法,获得一个数组,然后打印
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

public class Test10 {
    public void test01(Map<String,User> map, List<User> list){
        System.out.println("test01");
    }
    public Map<String,User> test02(){
        System.out.println("test02");
        return null;
    }

    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Test10.class.getMethod("test01", Map.class, List.class);
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("#"+genericParameterType);
            if (genericParameterType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
        method = Test10.class.getMethod("test02",null);
        Type genericReturnType = method.getGenericReturnType();

        if (genericReturnType instanceof  ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }
}

反射操作注解

  • ORM:Object relationship Mapping–>对象关系映射
  • 类和表结构对应,一个class类在数据库中对应一个表
  • 属性和字段对应
  • 对象和记录对应
import java.lang.annotation.*;
import java.lang.reflect.Field;

public class Test11 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.yjj.reflection.Student2");

        //通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);//@com.yjj.reflection.TableYjj(value=db_student)
        }

        //获得注解的value值
        TableYjj tableYjj = (TableYjj) c1.getAnnotation(TableYjj.class);
        String value = tableYjj.value();//类注解的value值
        System.out.println(value);//value=db_student

        //获得类指定的注解
        Field f = c1.getDeclaredField("name");//选属性
        FieldYjj annotation = f.getAnnotation(FieldYjj.class);//获得属性的所有注解
        System.out.println(annotation.columnName()+" "+annotation.type()+" "+annotation.length());//返回具体值
    }
}
@TableYjj("db_student")
class Student2{

    @FieldYjj(columnName = "db_name",type = "varchar",length = 3)
    private String name;
    @FieldYjj(columnName = "db_age",type = "int",length = 10)
    private int age;
    @FieldYjj(columnName = "db_id",type = "int",length = 10)
    private int id;

    public Student2(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }

    public Student2() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Student2{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", id=" + id +
                '}';
    }
}

//类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableYjj{
    String value();
}

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldYjj{
    String columnName();//列名
    String type();//类型
    int length();//长度
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值