Java反射及使用

java反射及使用

​ 涉及知识点:

  • Class对象
  • 对象创建方式

java中的反射主要是为了从Class对象中获取信息,而Class对象中的信息无非就是类名,属性,方法,方法参数,方法返回值,注解和泛型信息;与之对应的就是Class,Feild,Method,Param,Annotation和Type。

API调用

​ 这里假设如下的对象和接口

​ User类用于测试简单的反射调用,一般反射会和注解一起配合使用;我的理解是注解就是标记,当发现该注解被使用;则应该利用反射添加什么逻辑。

public class User {

    public String name;
    private int age;

    public void sayHi() {
        System.out.println("hi");
    }

    private int talkMoney() {
        return 100;
    }

    public String talkAno(String ano) {
        return "love " + ano;
    }

    public int getAge() {
        return age;
    }
}

​ RemoteServer实际是一个接口;在接口上标注注解的一种用法是利用注解 + 反射,生成该接口的代理对象。在之后的文章中,会使用这样的思想实现一个简单的WebFlux框架;利用接口和注解,直接访问远程服务器中RestFUL接口。

@ClassAnnotation("RemoteServer")
public interface RemoteServer {
    @MethodAnnotation(name = "url//")
    int getUserAge(@ParamAnnotation(name = "a")String name,int age);

    List<User> getUsers();

    void getBuffer(List<User> users);
}
获取Class对象
//1.使用类名获取
Class<User> clazz = User.class;
User user = new User();
//2.使用对象获取
Class<? extends User> clazz = user.getClass();
获取Method及Method信息
不带泛型信息
public static void getMethod() throws NoSuchMethodException {
        Class<User> userClass = User.class;
        System.out.println("===获取所有公共方法,包含从父类中继承得到的方法===");
        Method[] methods = userClass.getMethods();
        Arrays.stream(methods).forEach(System.out::println);
  
        System.out.println("===当前类的所有方法,不包含父类中继承得到的方法===");
        Method[] declaredMethods = userClass.getDeclaredMethods();
        Arrays.stream(declaredMethods).forEach(System.out::println);
  
        System.out.println("===获取方法的参数类型===");
        Method talkAno = userClass.getMethod("talkAno", String.class);
        Parameter[] parameters = talkAno.getParameters();
        System.out.println(parameters[0].getType());
        System.out.println(talkAno.getParameterTypes()[0]);
  
        System.out.println("===获取方法的返回值类型===");
        Class<?> returnType = talkAno.getReturnType();
        System.out.println(returnType);
    }

带泛型信息

​ 在方法中的返回值和参数中;很多会使用泛型;当需要动态代理或反射执行这些方法时,则需要知道这些泛型参数或返回值当实际类型。

​ 在java中,泛型的获取较为复杂,甚至需要类型强转。但是其使用思路大致一致。

  1. 获取代表返回值类型的Type,方法参数的Parameter对象
  2. 先判断当前Type或Parameter是否是泛型(ParameterizedType)。
  3. 强转为ParameteredType对象,调用getActualTypeArguments()方法获取Type[]数组,
  4. 将Type强转为Class对象,就是该Type或是Parameter的泛型类型。
public sataic void getMethodGen() throws Exception {
  			System.out.println("=== 获取返回值的泛型类型 ===");
        Method getUsers = remoteServerClass.getMethod("getUsers");
        Type genericReturnType = getUsers.getGenericReturnType();
        if (!(genericReturnType instanceof ParameterizedType)) {//判断
            System.out.println("current return type is not an typeof type");
            return;
        }
        Type[] actualTypeArguments = ((ParameterizedType) genericReturnType)
          .getActualTypeArguments();
        Arrays.stream(actualTypeArguments)
          .map(ata -> (Class) ata)
          .filter(c -> c == User.class)
          .forEach(System.out::println);

        System.out.println("=== 获取参数中的泛型类型 ===");
        Method getBuffer = remoteServerClass.getMethod("getBuffer", List.class);
        Arrays.stream(getBuffer.getParameters())
          .filter(parameter -> parameter.getParameterizedType() != null)
                .map(parameter -> {
                    Type parameterizedType = parameter.getParameterizedType();
                    Type[] ata = ((ParameterizedType) parameterizedType)
                      .getActualTypeArguments();
                    return (Class)ata[0];
                })
          .forEach(System.out::println);
}
获取Field
public static void getField() throws Exception {
    Class<User> userClass = User.class;
    System.out.println("===获取public field 类型===");
    Arrays.stream(userClass.getFields()).forEach(System.out::println);
  
    System.out.println("===获取private field 类型===");
    Field age = userClass.getDeclaredField("age");
    System.out.println(age.getType());
  
    System.out.println("===获取field中的值===");
    User user = new User();
    user.name = "jky";
    Field ageField = user.getClass().getDeclaredField("age");
    ageField.setAccessible(true);//开启访问私有域权限
    ageField.set(user, 24);
    ageField.setAccessible(false);
    System.out.println(user.getClass().getField("name").get(user));
    System.out.println(user.getAge());
}
获取Annotation
public static void getAnnotation() throws Exception {
        Class<RemoteServer> remoteServerClass = RemoteServer.class;
        System.out.println("===获取类上的注解===");
        ClassAnnotation annotation = remoteServerClass.getAnnotation(ClassAnnotation.class);
        System.out.println(annotation + " value " + annotation.value());
        System.out.println("=== 获取方法注解 ===");
        Method getUserAge = remoteServerClass.getMethod("getUserAge", String.class);
        Arrays.stream(getUserAge.getAnnotations())
          .filter(a -> a instanceof MethodAnnotation)
          .forEach(a -> {
            System.out.println(a);
            System.out.println(((MethodAnnotation) a).name());
        });
        System.out.println("=== 获取方法参数注解 ===");
        Arrays.stream(getUserAge.getParameters())
          .filter(parameter -> {
            ParamAnnotation annotation1 = parameter.getAnnotation(ParamAnnotation.class);
            return annotation1 != null;
        }).map(parameter -> parameter.getAnnotation(ParamAnnotation.class))
          .forEach(pa -> {
            System.out.println(pa);
            System.out.println(pa.name());
        });
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值