论坛网站建设方案,怎么提升网站的排名,网站开发国内外研究状况,wordpress搭建微信小程序1. 何为反射#xff1f;
反射#xff08;Reflection#xff09;机制指的是程序在运行的时候能够获取自身的信息。具体来说#xff0c;反射允许程序在运行时获取关于自己代码的各种信息。如果知道一个类的名称或者它的一个实例对象#xff0c; 就能把这个类的所有方法和变…1. 何为反射
反射Reflection机制指的是程序在运行的时候能够获取自身的信息。具体来说反射允许程序在运行时获取关于自己代码的各种信息。如果知道一个类的名称或者它的一个实例对象 就能把这个类的所有方法和变量的信息(方法名变量名方法修饰符类型方法参数等等所有信息)找出来。这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。简单来说就是面向对象看待一个类即以面向对象的思想来抽象一个类。
反射是一种强大的功能广泛应用于框架设计、依赖注入、单元测试和动态代理等领域。然而由于反射会绕过编译时的类型安全检查所以使用不当可能会导致更高的运行时错误几率和性能开销。因此在使用反射时需要格外谨慎以避免潜在的风险。
2. 反射的意义所在 通过反射机制可以让程序创建和控制任何类的对象无需提前硬编码目标类。使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。反射机制是构建框架技术的基础所在使用反射可以避免将代码写死在框架中。 不过反射也存在明显的缺点使用反射性能较低需要解析字节码且如果将内存中的对象进行解析相对不安全会破坏封装性。
3. 通过反射实例化对象
在Java中可以通过反射获取类的构造器、方法、字段等信息
class Test {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {// 下面这段代码是以反射机制的方式创建对象。// 通过反射机制获取Class通过Class来实例化对象Class c Class.forName(com.reflectBean.User);// newInstance() 这个方法会调用User这个类的无参数构造方法完成对象的创建。// 重点是newInstance()调用的是无参构造必须保证无参构造是存在的Object obj c.newInstance();Method method c.getMethod(myMethod);method.invoke(obj);}
}
4. 获取Class类的三种方式
在Java编程中获取 Class 对象的三种常用方式如下
1. 通过类名的静态属性 class: 这是获取 Class 对象最简单的方法适用于已知编译时类型的情况。
ClassMyClass clazz MyClass.class;
2. 通过对象的实例方法 getClass: 这是在运行时获取一个对象的 Class 对象的方法适用于已知一个实例化对象的情况。
MyClass obj new MyClass();
Class? extends MyClass clazz obj.getClass();
3. 通过类名的字符串 forName: 这是动态加载类的一种方式特别有用在类名只有在运行时才能确定的情况下。
try {Class? clazz Class.forName(com.reflectBean.User);
} catch (ClassNotFoundException e) {e.printStackTrace();
}
5. 常用的Class类的方法
Class 类在 Java 中定义了大量的方法可以用来反射性地获取类的各种信息或进行操作。不过需要注意的是在使用反射进行私有成员访问时需要设置相应的访问权限如 setAccessible(true)。以下是一些常用的方法
1. 类信息获取方法 getName()返回完整类名带包名。 getSimpleName()获取类的简单名称。 getCanonicalName()获取类的规范名称。 getPackage()获取类所在的包。 getModifiers()获取类的修饰符如 public, abstract, final 等。 2. 构造函数相关方法 getConstructor(Class?... parameterTypes)获取指定参数类型的公共构造函数。 getConstructors()获取所有公共构造函数。 getDeclaredConstructor(Class?... parameterTypes)获取指定参数类型的任意包括私有构造函数。 getDeclaredConstructors()获取所有任意包括私有构造函数。 3. 方法相关方法 getMethod(String name, Class?... parameterTypes)获取指定名称和参数类型的公共方法。getMethods()获取所有公共方法包括从父类继承的方法。getDeclaredMethod(String name, Class?... parameterTypes)获取指定名称和参数类型的任意方法。getDeclaredMethods()获取所有任意方法包括私有。 4. 字段成员变量相关方法 getField(String name)获取指定名称的公共字段。getFields()获取所有公共字段。getDeclaredField(String name)获取指定名称的任意字段。getDeclaredFields()获取所有任意字段包括私有。 5. 类层次结构相关方法 getSuperclass()获取父类。getInterfaces()获取实现的接口。isAssignableFrom(Class? cls)判断当前类或接口是否可以从指定类型的对象赋值即能否进行类型转换。 6. 实例创建方法 newInstance()创建类的实例需要无参构造函数。 7. 其他方法 getAnnotations()获取类上的注解。isAnnotation()判断类是否是注解类型。isInterface()判断是否为接口。isArray()判断是否为数组。isPrimitive()判断是否为基本数据类型。isInstance(Object obj)判断给定对象是否为该 Class 的实例。 6. 获取Field的四种方式
在Java中可以通过Class对象获取某个类的字段FieldField类代表类的成员变量。获取 Field的几种常用方式如下
1. 通过字段名获取公共字段 (public 属性)
try {Class? clazz Class.forName(com.reflectBean.User);Field field clazz.getField(userName);// 对 field 进行操作// ...} catch (NoSuchFieldException | ClassNotFoundException e) {e.printStackTrace();
}2. 获取所有公共字段 (public 属性)
try {Class? clazz Class.forName(com.reflectBean.User);Field[] fields clazz.getFields();for (Field field : fields) {// 对每个 field 进行操作// ... }
} catch (ClassNotFoundException e) {e.printStackTrace();
}3. 通过字段名获取任何字段包括私有、保护和包访问属性
try {Class? clazz Class.forName(com.reflectBean.User);Field field clazz.getDeclaredField(password);// 允许访问私有字段field.setAccessible(true); // 对 field 进行操作比如设置可访问性field.setAccessible(true);
} catch (NoSuchFieldException | ClassNotFoundException e) {e.printStackTrace();
}4. 获取所有字段包括私有、保护和包访问属性
try {Class? clazz Class.forName(com.reflectBean.User);Field[] fields clazz.getDeclaredFields();for (Field field : fields) {// 对每个 field 进行操作比如设置可访问性field.setAccessible(true);}
} catch (ClassNotFoundException e) {e.printStackTrace();
}7. 常用的Field类的方法
在Java中Field类提供了许多方法用于获取和操作类的字段成员变量。以下是一些常用的方法
1. 获取字段信息的方法 getName()返回字段的名称。getType()返回表示字段类型的 Class 对象。getGenericType()返回表示字段的 Type 对象包括泛型类型信息。getModifiers()返回字段的修饰符整数编码使用 Modifier 类中的方法可以解码。 2. 访问和修改字段值的方法 get(Object obj)从指定对象中获取该字段的值。getByte(Object obj)从指定对象中获取该字段的值byte类型。set(Object obj, Object value)将指定对象的该字段设置为新的值。 3. 访问控制 setAccessible(boolean flag)设置字段的可访问性。即使字段是私有的通过设置可访问性也可以访问它。 8. 获取Method的四种方式
在Java中可以通过反射机制获取类的方法Method对象。以下是几种常用的方法获取方式
1. 通过方法名和参数类型获取公共方法
try {// 获取类的Class对象Class? clazz Class.forName(com.reflectBean.User);// 通过方法名和参数类型获取公共方法Method method clazz.getMethod(publicMethod, String.class);// 调用方法method.invoke(null, 参数);} catch (Exception e) {e.printStackTrace();}
2. 获取所有公共方法
try {// 获取类的Class对象Class? clazz Class.forName(com.reflectBean.User);// 获取所有公共方法Method[] methods clazz.getMethods();// 遍历所有方法for (Method method : methods) {// 获取方法名String methodName method.getName();// 判断方法名是否为getNameif (methodName.equals(getName)) {// 执行getName方法Object result method.invoke(user);System.out.println(result);}}} catch (Exception e) {e.printStackTrace();}
3. 通过方法名和参数类型获取任意方法包括私有、保护和默认访问权限的方法
try {// 获取类的Class对象Class? clazz Class.forName(com.reflectBean.User);// 通过方法名和参数类型获取任意方法Method method clazz.getDeclaredMethod(privateMethod, int.class);// 调用方法method.invoke(new com.reflectBean.User(), 100);// 允许访问私有方法method.setAccessible(true);} catch (Exception e) {e.printStackTrace();}
4. 获取所有的任意方法包括私有、保护和默认访问权限的方法
try {// 获取类的Class对象Class? clazz Class.forName(com.example.MyClass);// 获取所有任意方法Method[] methods clazz.getDeclaredMethods();for (Method method : methods) {// 对每个 method 进行操作// ...}} catch (Exception e) {e.printStackTrace();}
9. 常用的Method的方法
Method类在Java反射中提供了许多方法这些方法可以用于获取方法的各类信息、调用方法以及操作注解等。以下是一些常用的Method类方法
1. 获取方法信息的方法 String getName()获取方法的名称。Class? getDeclaringClass()获取声明此方法的类或接口的Class对象。Class? getReturnType()获取方法的返回类型。Type getGenericReturnType()获取方法的泛型返回类型。Class?[] getParameterTypes()获取方法的参数类型数组。Type[] getGenericParameterTypes()获取方法的泛型参数类型数组。int getParameterCount()获取方法的参数数量。Class?[] getExceptionTypes()获取方法声明的异常类型数组。Type[] getGenericExceptionTypes()获取方法声明的泛型异常类型数组。int getModifiers()获取方法的修饰符用于确定方法是public、private、protected、static等。Annotation[][] getParameterAnnotations()获取方法的参数上的注解。String toGenericString()返回描述方法的字符串包括泛型信息。 2. 调用方法 Object invoke(Object obj, Object... args)调用此Method对象表示的底层方法。 3. 注解相关的方法 T extends Annotation T getAnnotation(ClassT annotationClass)获取指定类型的注解。Annotation[] getAnnotations()获取此方法上存在的所有注解。Annotation[] getDeclaredAnnotations()获取直接存在于此方法上的所有注解。T extends Annotation T getDeclaredAnnotation(ClassT annotationClass)获取直接存在于此方法上的指定类型的注解。T extends Annotation T[] getDeclaredAnnotationsByType(ClassT annotationClass)获取直接存在于此方法上的指定类型的所有注解。T extends Annotation T getAnnotationsByType(ClassT annotationClass)获取此方法上存在的指定类型的所有注解。boolean isAnnotationPresent(Class? extends Annotation annotationClass)判断此方法上是否存在指定类型的注解。 4. 设置和获取访问控制 void setAccessible(boolean flag)设置方法的可访问性。如果是 true则强制使能此方法即使它是私有的。boolean isAccessible()判断此方法是否可以通过反射执行。 5. 其他常用方法 boolean isSynthetic()判断此方法是否是编译器生成的合成方法。boolean isVarArgs()判断此方法是否接受可变数量的参数。 10. 实践出真知
好了扯了那么久反射的概念和基础使用接下来结合反射的内容我们来简单演示通过反射去实现一些基本业务。
10.1 如何通过反射获取和设置对象私有字段的值 先捋清楚思路获取和设置对象私有字段的值大致可以分为四个步骤实现 1. 获取对象的 Class 对象。 2. 通过反射获取私有字段 Field 对象。 3. 设置字段的可访问性为 true以绕过 Java 语言访问检查。 4. 通过反射获取和设置字段的值。 那么接下来演示下代码的实现流程
假设有一个包含私有字段的类AccountBalance.class
public class AccountBalance {// 设置初始值为100private BigDecimal balance new BigDecimal(100);// 默认构造函数public AccountBalance() {}// 打印字段值的方法public void printField() {System.out.println(当前的账户余额为: balance);}
}
接下来我们来演示下怎么通过反射获取账户余额然后变更私有字段
public class Test {public static void main(String[] args) {try {// 创建 AccountBalance 对象实例AccountBalance account new AccountBalance();// 获取 AccountBalance 的 Class 对象Class? clazz account.getClass();// 获取私有字段Field privateField clazz.getDeclaredField(balance);// 设置字段的可访问性为 trueprivateField.setAccessible(true);// 获取私有字段的值BigDecimal initBlance (BigDecimal) privateField.get(account);System.out.println(最初的账号余额为 initBlance);// 设置私有字段的值privateField.set(account, new BigDecimal(50));// 验证字段值已经更新initBlance (BigDecimal) privateField.get(account);System.out.println(本次扣除的账户余额为 initBlance);// 使用类的方法验证字段被正确修改account.printField();} catch (NoSuchFieldException | IllegalAccessException e) {e.printStackTrace();}}
}
控制台输出 10.2 如何用反射机制创建对象呢 依旧是先整理下步骤使用反射机制创建对象大致可分为3个步骤 1. 获取类的Class对象。 2. 通过Class对象获取构造方法构造器。注意这里虽然可以通过Class对象的newInstance方法简单地创建一个类的实例但是这种方式只能调用无参构造函数故该实例不给予演示。 3. 使用构造方法创建类的实例。 还是假设我们有一个包含无参和有参数构造函数的类AccountBalance.class
public class AccountBalance {// 设置初始值为100private BigDecimal balance new BigDecimal(100);// 默认构造函数public AccountBalance() {System.out.println(调用无参构造函数);}// 有参构造函数public AccountBalance(BigDecimal initialBalance) {this.balance initialBalance;System.out.println(调用带参数的构造函数初始化余额为 initialBalance);}// 打印字段值的方法public void printField() {System.out.println(当前的账户余额为: balance);}
}
使用Constructor.newInstance()创建对象并访问其方法
public void Test {public static void main(String[] args) {try {// 获取 AccountBalance 的 Class 对象Class? clazz Class.forName(com.example.AccountBalance);// 获取有参构造函数Constructor? constructor clazz.getConstructor(BigDecimal.class);// 使用构造函数创建实例并传递参数Object obj constructor.newInstance(new BigDecimal(200));// 验证对象创建成功通过调用方法Method printMethod clazz.getMethod(printField);printMethod.invoke(obj);} catch (Exception e) {e.printStackTrace();}}} 10.3 如何反编译一个类的构造方法 反编译一个类的构造方法大致可以分为四个步骤实现 1. 获取需要被反编译的类的Class对象 2. 获取类所有声明的构造方法 3. 循环遍历所有的构造方法 4. 获取每个构造方法的修饰符、参数类型并格式化输出 我们仍然以AccountBalance类为例进行说明。
public class AccountBalance {// 设置初始值为100private BigDecimal balance new BigDecimal(100);// 默认构造函数public AccountBalance() {System.out.println(调用无参构造函数);}// 有参构造函数public AccountBalance(BigDecimal initialBalance) {this.balance initialBalance;System.out.println(调用带参数的构造函数初始化余额为 initialBalance);}// 打印字段值的方法public void printField() {System.out.println(当前的账户余额为: balance);}
}
进行反编译构造方法流程
public void Test {public static void main(String[] args) {try {// 获取 AccountBalance 的 Class 对象Class? clazz Class.forName(com.example.AccountBalance);// 获取所有声明的构造方法包括私有构造方法Constructor?[] constructors clazz.getDeclaredConstructors();for (Constructor? constructor : constructors) {// 获取构造方法的修饰符String modifiers Modifier.toString(constructor.getModifiers());// 获取构造方法的参数类型Class?[] parameterTypes constructor.getParameterTypes();StringBuilder params new StringBuilder();for (int i 0; i parameterTypes.length; i) {params.append(parameterTypes[i].getSimpleName());if (i parameterTypes.length - 1) {params.append(, );}}// 打印构造方法的详细信息System.out.println(modifiers clazz.getSimpleName() ( params ) { });}} catch (ClassNotFoundException e) {e.printStackTrace();}}} 10.4 给定一个类如何获取这个类的基类以及实现的接口呢 这种问题的思路需要考虑两点 1. 怎么获取该类的父类这点可以使用Class提供的getSuperClass()方法来获取。 2. 怎么获取类的接口这点可以使用Class提供的getInterfaces()方法获取实现的接口。 假设定义了以下类和接口ChildClass.class 和 Parent.class、Car.java。
public class ChildClass extends ParentClass implements Car {}
public class ParentClass {}
public interface Car {
}
获取一个类的父类和实现的接口的具体示例
public static void main(String[] args) throws ClassNotFoundException {try {// 获取 ChildClass 的 Class 对象Class? clazz Class.forName(com.example.ChildClass);// 获取父类Class? superClass clazz.getSuperclass();System.out.println(父类: superClass.getName());// 获取实现的接口Class?[] interfaces clazz.getInterfaces();System.out.println(实现的接口:);for (Class? iface : interfaces) {System.out.println(iface.getName());}} catch (ClassNotFoundException e) {e.printStackTrace();}
}
11. 总结
反射机制是Java语言中一种强大的功能它让我们能够在运行时进行一些本应只能在编译时完成的操作。这个功能的特点就是使得程序可以动态地检查和操作类、方法、字段等从而带来了极大的灵活性。简单来说反射机制使得开发人员能够编写更加灵活和动态的代码。举个例子我们可以根据配置文件来动态创建对象、实现依赖注入、在运行时调用方法而不需要提前知道方法的名称。
然而反射机制虽然给我们带来了好处但也有一些弊端需要注意。首先反射通常会比直接调用要慢因为它会绕过一些编译时的优化。其次由于反射机制允许操作私有成员可能会破坏封装性和安全性。最后使用反射的代码可读性降低同时也更难以维护和调试。因此在使用反射时需要谨慎考虑其影响。
文章转载自: http://www.morning.srwny.cn.gov.cn.srwny.cn http://www.morning.mnnxt.cn.gov.cn.mnnxt.cn http://www.morning.xdmsq.cn.gov.cn.xdmsq.cn http://www.morning.tntgc.cn.gov.cn.tntgc.cn http://www.morning.zcqgf.cn.gov.cn.zcqgf.cn http://www.morning.fxygn.cn.gov.cn.fxygn.cn http://www.morning.bqdpy.cn.gov.cn.bqdpy.cn http://www.morning.trsfm.cn.gov.cn.trsfm.cn http://www.morning.kcrw.cn.gov.cn.kcrw.cn http://www.morning.xmttd.cn.gov.cn.xmttd.cn http://www.morning.kllzy.com.gov.cn.kllzy.com http://www.morning.plqhb.cn.gov.cn.plqhb.cn http://www.morning.hhzdj.cn.gov.cn.hhzdj.cn http://www.morning.mqgqf.cn.gov.cn.mqgqf.cn http://www.morning.lxhny.cn.gov.cn.lxhny.cn http://www.morning.twgzq.cn.gov.cn.twgzq.cn http://www.morning.spxk.cn.gov.cn.spxk.cn http://www.morning.errnull.com.gov.cn.errnull.com http://www.morning.yuanshenglan.com.gov.cn.yuanshenglan.com http://www.morning.rfbt.cn.gov.cn.rfbt.cn http://www.morning.bsrp.cn.gov.cn.bsrp.cn http://www.morning.rzjfn.cn.gov.cn.rzjfn.cn http://www.morning.gjsjt.cn.gov.cn.gjsjt.cn http://www.morning.cfynn.cn.gov.cn.cfynn.cn http://www.morning.jwpcj.cn.gov.cn.jwpcj.cn http://www.morning.btns.cn.gov.cn.btns.cn http://www.morning.lxmmx.cn.gov.cn.lxmmx.cn http://www.morning.tllws.cn.gov.cn.tllws.cn http://www.morning.zcqgf.cn.gov.cn.zcqgf.cn http://www.morning.fjscr.cn.gov.cn.fjscr.cn http://www.morning.mbdbe.cn.gov.cn.mbdbe.cn http://www.morning.qlpq.cn.gov.cn.qlpq.cn http://www.morning.clkyw.cn.gov.cn.clkyw.cn http://www.morning.nbpqx.cn.gov.cn.nbpqx.cn http://www.morning.kcfnp.cn.gov.cn.kcfnp.cn http://www.morning.gyzfp.cn.gov.cn.gyzfp.cn http://www.morning.tlzbt.cn.gov.cn.tlzbt.cn http://www.morning.ltrz.cn.gov.cn.ltrz.cn http://www.morning.rfzbm.cn.gov.cn.rfzbm.cn http://www.morning.zlkps.cn.gov.cn.zlkps.cn http://www.morning.rdsst.cn.gov.cn.rdsst.cn http://www.morning.rlns.cn.gov.cn.rlns.cn http://www.morning.ppzgr.cn.gov.cn.ppzgr.cn http://www.morning.qzpqp.cn.gov.cn.qzpqp.cn http://www.morning.jbmsp.cn.gov.cn.jbmsp.cn http://www.morning.yxshp.cn.gov.cn.yxshp.cn http://www.morning.nmwgd.cn.gov.cn.nmwgd.cn http://www.morning.yhpl.cn.gov.cn.yhpl.cn http://www.morning.rfgc.cn.gov.cn.rfgc.cn http://www.morning.thwcg.cn.gov.cn.thwcg.cn http://www.morning.ybnps.cn.gov.cn.ybnps.cn http://www.morning.jgcxh.cn.gov.cn.jgcxh.cn http://www.morning.cnxpm.cn.gov.cn.cnxpm.cn http://www.morning.mkczm.cn.gov.cn.mkczm.cn http://www.morning.zlchy.cn.gov.cn.zlchy.cn http://www.morning.ydnxm.cn.gov.cn.ydnxm.cn http://www.morning.dfdhx.cn.gov.cn.dfdhx.cn http://www.morning.jxjrm.cn.gov.cn.jxjrm.cn http://www.morning.srtw.cn.gov.cn.srtw.cn http://www.morning.tkyxl.cn.gov.cn.tkyxl.cn http://www.morning.cldgh.cn.gov.cn.cldgh.cn http://www.morning.wfykn.cn.gov.cn.wfykn.cn http://www.morning.dfkmz.cn.gov.cn.dfkmz.cn http://www.morning.smdkk.cn.gov.cn.smdkk.cn http://www.morning.hpspr.com.gov.cn.hpspr.com http://www.morning.chxsn.cn.gov.cn.chxsn.cn http://www.morning.nqgds.cn.gov.cn.nqgds.cn http://www.morning.dkqyg.cn.gov.cn.dkqyg.cn http://www.morning.qtrlh.cn.gov.cn.qtrlh.cn http://www.morning.dztp.cn.gov.cn.dztp.cn http://www.morning.pluimers.cn.gov.cn.pluimers.cn http://www.morning.lpcpb.cn.gov.cn.lpcpb.cn http://www.morning.dgmjm.cn.gov.cn.dgmjm.cn http://www.morning.zqnmp.cn.gov.cn.zqnmp.cn http://www.morning.prfrb.cn.gov.cn.prfrb.cn http://www.morning.bpmtx.cn.gov.cn.bpmtx.cn http://www.morning.wfykn.cn.gov.cn.wfykn.cn http://www.morning.qdcpn.cn.gov.cn.qdcpn.cn http://www.morning.cknws.cn.gov.cn.cknws.cn http://www.morning.nhpmn.cn.gov.cn.nhpmn.cn