Java 基础知识之 Java 反射
发布日期:2021-06-29 12:02:50
浏览次数:2
分类:技术文章
本文共 12044 字,大约阅读时间需要 40 分钟。
什么是Java反射?
Java 反射机制是 Java 自诞生以来就具备的能力,用于在 Java 程序运行过程中动态的获取类的信息,调用类中的方法。
Java 反射的使用场景
- 获取类的信息:如 Spring 中通过读取类的注解信息注册 Bean 对象。
- 调用类的方法:Spring 可以读取 XML 的配置信息,选择恰当的构造器,通过反射实例化 Bean 对象。
Java 反射机制提供了哪些 API ?
Java 虚拟机将字节码加载到内存中,并且抽象出了一些 Java 类。当程序运行时,可以通过这些类获取字节码中类的元信息。
Java反射的包名为java.lang.reflect
,主要的 UML 类图如下。
- Class:表示Java类。
- Field:表示Java类中的成员变量。
- Method:表示Java类中的成员方法。
- Constructor:表示Java类的构造方法。
其他类如下:
- Array:表示数组。
- AnnotatedElement:JDK 1.5 新增,泛型相关,表示可以被注解标注的元素,如类、成员变量、 方法等。
- Member:表示 Java 类中的成员,如成员变量,成员方法,构造方法。
- AccessibleObject:JDK 1.2 新增,Field、Method、Constructor的父接口,提供对反射对象抑制默认的 Java 访问控制检查的能力。
- GenericDeclaration:JDK 1.5 新增,泛型相关,表示可以定义类型变量的元素。
- Type:JDK 1.5 新增,表示 Java 中的某一种类型。
- Parameter:JDK 1.8 新增,表示成员方法或构造方法中的某一个参数。
- AnnotatedType:JDK 1.8 新增,表示可以被注解标注的类型。
- Executable:JDK 8 新增,Method 和 Constructor 的父接口。
- TypeVariable:JDK 1.5 新增,泛型相关,类型变量,如List 中的 T。
- GenericArrayType:JDK 1.5 新增,泛型相关,泛型数组类型,如 T[] 。
- ParameterizedType:JDK 1.5 新增,泛型相关,参数化类型,如 Class 。
- WildcardType:JDK 1.5 新增,泛型相关,通配符类型,如 Class<? extend Number> 中的
? extend Number
。
Class 类
Class 类表示 Java 中的某一个类,不包含类的泛型信息。
获取方式主要有三种,如下:
java.lang.Class#forName(java.lang.String)
:如Class<?> cls = Class.forName("com.mysql.cj.jdbc.Driver")
。java.lang.Object#getClass
:如Class<?> cls = "hello,java".getClass()
。Type.class
:如Class<?> cls = String.class
。
Class 类中常用的方法如下:
类定义相关方法
方法 | 用途 |
---|---|
public static Class<?> forName(String className) | 根据类名称获取Class对象 |
public static Class<?> forName(String name, boolean initialize,ClassLoader loader) | 根据类名称获取Class对象 |
public Package getPackage() | 获取类的包信息 |
public native int getModifiers() | 获取类的修饰符 |
public native Class<? super T> getSuperclass() | 获取当前类的父类 |
public Type getGenericSuperclass() | 获取泛型父类型 |
public AnnotatedType getAnnotatedSuperclass() | 获取表示当前类的父类的AnnotatedType对象 |
public String getSimpleName() | 获取表示当前类的简单名称 |
public Class<?>[] getInterfaces() | 获取接口数组 |
public Type[] getGenericInterfaces() | 获取泛型接口数组 |
public AnnotatedType[] getAnnotatedInterfaces() | 获取表示当前类的接口的AnnotatedType数组 |
public Class<?>[] getClasses() | 获取当前类和其父类公有内部类数组 |
public Class<?> getDeclaringClass() throws SecurityException | 获取定义当前内部类的外部类,如果当前内部类是匿名内部类返回null |
public XXX<?> getEnclosingXXX() throws SecurityException | 获取当前匿名内部类所在的类/构造方法/成员方法,XXX 表示 Class/Constructor/Method |
类成员相关方法
类成员包括内部类、构造方法(Constructor)、成员变量(Field)和成员方法(Method)。
下表中的 XXX 可以表示 Field、Constructor 或者 Method。
方法 | 用途 |
---|---|
public XXX getDeclaredXXX(…) | 获取当前类定义中给定参数指定的成员变量/构造方法/成员方法 |
public XXX[] getDeclaredXXXs() throws SecurityException | 获取当前类定义的所有内部类(Class)/成员变量/构造方法/成员方法 |
public XXX getXXX(…) | 获取当前类及其父类中给定参数的共有成员变量/构造方法/成员方法 (构造方法只获取当前类中定义的) |
public XXX[] getXXXs() throws SecurityException | 获取当前类及其父类中所有共有内部类(Class)/成员变量/构造方法/成员方法 (构造方法只获取当前类中定义的) |
其他方法
方法 | 用途 |
---|---|
public boolean isAnnotation() | 当前类是否为注解 |
public boolean isAnonymousClass() | 当前类是否为匿名内部类 |
public native boolean isArray() | 当前类是否为数组 |
public native boolean isAssignableFrom(Class<?> cls) | 当前类是否为给定类的父类 |
public boolean isEnum() | 当前类是否表示枚举类 |
public native boolean isInstance(Object obj) | 当前类是否为给定对象的类型 |
public native boolean isInterface() | 当前类是否表示接口 |
public boolean isLocalClass() | 当前类是否为局部内部类 |
public boolean isMemberClass() | 当前类是否为成员内部类 |
public native boolean isPrimitive() | 当前类是否表示基本数据类型 |
public boolean isSynthetic() | 当前类是否为编译期自动生成的类 |
public native Class<?> getComponentType() | 获取当前数组类的元素类型 |
public T[] getEnumConstants() | 获取当前枚举类的对象数组 |
public Class<? extends U> asSubclass(Class clazz) | 将当前Class对象转换为指定Class对象的子类 |
public T cast(Object obj) | 将给定对象转换为当前Class对象表示的类或接口 |
public T newInstance() | 使用当前类的无参构造方法实例化对象 |
public ClassLoader getClassLoader() | 获取当前类的类加载器 |
public String getName() | 获取类的名称 |
public String getCanonicalName() | 获取 Java 语言规范定义的底层类的名称 |
public String toGenericString() | 获取当前类的字符串描述信息 |
Field 类
Field 通过 Class 的 getDeclaredField(…)、getDeclaredFields()、getField(…) 或者 getFields() 方法获取,主要提供了设置和获取成员变量值的方法。
具体如下,其中XXX可以表示 Boolean、Byte、Char、Short、Int、Long、Float、Double。方法 | 用途 |
---|---|
public xXX getXXX(Object obj) throws IllegalArgumentException, IllegalAccessException | 获取当前成员变量表示的 Java 基本类型的值 |
public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException | 获取当前成员变量表示的值 |
public void setXxx(Object obj, xxx b) throws IllegalArgumentException, IllegalAccessException | 将当前成员变量设置为给定的 Java 基本类型的值 |
public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException | 将当前成员变量设置为给定的值 |
Constructor 类
Constructor 表示构造方法,主要提供了实例化 Java 对象的方法,具体如下。
方法 | 用途 |
---|---|
public T newInstance(Object … initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException | 实例化 Java 对象 |
Method 类
Method 表示 Java 中的方法,经常用来调用方法,主要的方法如下。
方法 | 用途 |
---|---|
public Object getDefaultValue() | 获取注解中属性的默认值 |
public Type getGenericReturnType() | 获取方法返回泛型类型 |
public Class<?> getReturnType() | 获取方法返回类型 |
public Object invoke(Object obj, Object… args) | 调用方法 |
public boolean isBridge() | 方法是否为桥接方法 |
public boolean isDefault() | 方法是否为默认方法 |
反射使用示例
示例1,打印给定类的结构
代码如下:
package com.zzuhkp;import java.lang.annotation.Annotation;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.lang.reflect.Type;import java.util.Arrays;import java.util.stream.Collectors;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotNull;/** * @author zzuhkp * @date 2020-08-05 9:48 * @since 1.0 */public class ReflectTest { @NotBlank(message = "名称不能为空") private String name; public static void main(String[] args) { printClass(ReflectTest.class); } @Deprecated public static void printClass(@NotNull Class cls) { StringBuilder sb = new StringBuilder(); // 获取包信息 Package aPackage = cls.getPackage(); if (aPackage != null) { sb.append("package ").append(aPackage.getName()).append(";\n\n"); } // 获取类修饰符信息 String modifier = Modifier.toString(cls.getModifiers()); if (modifier.length() > 0) { sb.append(modifier).append(" "); } // 获取类名 sb.append("class ").append(cls.getSimpleName()).append(" "); // 获取父类 Type superclass = cls.getGenericSuperclass(); if (superclass != Object.class) { sb.append("extend ").append(superclass.getTypeName()).append(" "); } // 获取接口 Type[] interfaces = cls.getGenericInterfaces(); if (interfaces.length > 0) { String interfaceStr = Arrays.stream(interfaces).map(Type::getTypeName).collect(Collectors.joining(",")); sb.append("implements ").append(interfaceStr).append(" "); } sb.append("{\n\n"); // 获取成员变量 Field[] fields = cls.getDeclaredFields(); for (Field field : fields) { //获取成员变量的注解 for (Annotation annotation : field.getAnnotations()) { sb.append(" ").append(annotation).append("\n"); } // 获取成员变量修饰符 String fieldModifier = Modifier.toString(field.getModifiers()); // 获取成员变量类型名称 String fieldTypeName = field.getGenericType().getTypeName(); // 获取成员变量名称 String fieldName = field.getName(); sb.append(" ").append(fieldModifier).append(" ").append(fieldTypeName) .append(" ").append(fieldName).append(";\n"); } sb.append("\n"); Constructor [] constructors = cls.getDeclaredConstructors(); for (Constructor constructor : constructors) { for (Annotation annotation : constructor.getAnnotations()) { sb.append(" ").append(annotation).append("\n"); } sb.append(" "); // 获取构造方法修饰符 int constructorModifiers = constructor.getModifiers(); String methodModifier = Modifier.toString(constructorModifiers); if (methodModifier.length() > 0) { sb.append(methodModifier).append(" "); } // 获取构造方法名称 String constructorName = constructor.getName(); sb.append(constructorName).append("("); // 获取方法参数 String parameters = Arrays.stream(constructor.getParameters()) .map(parameter -> { // 获取方法参数注解 String str = Arrays.stream(parameter.getAnnotations()).map(Annotation::toString) .collect(Collectors.joining(" ")); if (str.length() > 0) { str = str + " "; } // 获取方法参数类型及名称 str = str + parameter.getParameterizedType().getTypeName() + " " + parameter.getName(); return str; }) .collect(Collectors.joining(",")); sb.append(parameters); sb.append(")"); if (!Modifier.isNative(constructorModifiers)) { sb.append("{\n").append(" ..\n").append(" }"); } else { sb.append(";"); } sb.append("\n"); } // 获取成员方法 Method[] methods = cls.getDeclaredMethods(); for (Method method : methods) { for (Annotation annotation : method.getAnnotations()) { sb.append(" ").append(annotation).append("\n"); } sb.append(" "); // 获取成员方法修饰符 int methodModifiers = method.getModifiers(); String methodModifier = Modifier.toString(methodModifiers); if (methodModifier.length() > 0) { sb.append(methodModifier).append(" "); } // 获取成员方法返回值类型 String returnType = method.getGenericReturnType().getTypeName(); sb.append(returnType).append(" "); // 获取成员方法名称 String methodName = method.getName(); sb.append(methodName).append("("); // 获取方法参数 String parameters = Arrays.stream(method.getParameters()) .map(parameter -> { // 获取方法参数注解 String str = Arrays.stream(parameter.getAnnotations()).map(Annotation::toString) .collect(Collectors.joining(" ")); if (str.length() > 0) { str = str + " "; } // 获取方法参数类型及名称 str = str + parameter.getParameterizedType().getTypeName() + " " + parameter.getName(); return str; }) .collect(Collectors.joining(",")); sb.append(parameters); sb.append(")"); if (!Modifier.isNative(methodModifiers)) { sb.append("{\n").append(" ..\n").append(" }"); } else { sb.append(";"); } sb.append("\n"); } sb.append("}"); System.out.println(sb); }}
执行结果如下:
package com.zzuhkp;public class ReflectTest { @javax.validation.constraints.NotBlank(message=名称不能为空, groups=[], payload=[]) private java.lang.String name; public com.zzuhkp.ReflectTest(){ .. } public static void main(java.lang.String[] args){ .. } private static java.lang.String lambda$printClass$1(java.lang.reflect.Parameter parameter){ .. } @java.lang.Deprecated() public static void printClass(@javax.validation.constraints.NotNull(message={ javax.validation.constraints.NotNull.message}, groups=[], payload=[]) java.lang.Class cls){ .. } private static java.lang.String lambda$printClass$0(java.lang.reflect.Parameter parameter){ .. }}
示例2,通过反射调用方法
代码如下:
public class ReflectTest { static class Test { private void sayHello() { System.out.println("你好,Java"); } } public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Test test = new Test(); Method method = Test.class.getDeclaredMethod("sayHello"); method.setAccessible(true); method.invoke(test); }}
执行结果如下:
你好,Java
可以看到,私有的方法也可以通过反射进行调用。
转载地址:https://blog.csdn.net/zzuhkp/article/details/107744185 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月22日 10时16分33秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
BLE蓝牙4.0串口调试助手
2019-04-29
树莓派WIFI设置
2019-04-29
用vcgencmd获取树莓派硬件状态数据
2019-04-29
IIS 多域名多张证书配置
2019-04-29
树莓派LINUX 截屏
2019-04-29
树莓派Raspberry Pi的嵌入式QT平台
2019-04-29
apache https
2019-04-29
Debian Jessie安装支持HTML5音视频的Chromium浏览器听百度音乐
2019-04-29
nanopi2 启动信息
2019-04-29
POS打印机驱动大全
2019-04-29
phpstudy https
2019-04-29
centos apache 最新版HTTPS配置
2019-04-29
树莓派添加中文语音合成功能
2019-04-29
kangle https设置
2019-04-29
Linux下EasyPanel版本安装及升级
2019-04-29
raspberry pi(树莓派) + easycap d60 视频采集
2019-04-29
WebRTC
2019-04-29
rfc5766-turn-server NAT
2019-04-29
webrtc详细教程
2019-04-29