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中,泛型的获取较为复杂,甚至需要类型强转。但是其使用思路大致一致。
- 获取代表返回值类型的Type,方法参数的Parameter对象
- 先判断当前Type或Parameter是否是泛型(ParameterizedType)。
- 强转为ParameteredType对象,调用getActualTypeArguments()方法获取Type[]数组,
- 将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());
});
}