大家都知道使用java反射可以在运行时动态改变对象的行为,甚至是private final的成员变量,但并不是所有情况下,都可以修改成员变量。今天就举几个小例子说明。
基本数据类型
/** * @author Cool-Coding 2018/5/15 */ public class ReflectionUsage {private final int age=18; public int getAge(){ return age; } }
测试代码:
import java.lang.reflect.Field; /** * @author Cool-Coding 2018/5/15 */ public class ReflectionTest { public static void main(String[] args){ try { Class reflectionUsage = Class.forName("practise.practise.ReflectionUsage"); ReflectionUsage o = (ReflectionUsage)reflectionUsage.newInstance(); Field age = reflectionUsage.getDeclaredField("age"); age.setAccessible(true); age.set(o,68); age.setAccessible(false); System.out.println(o.getAge()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); }catch (IllegalAccessException | InstantiationException e){ } } }
运行结果:18
此时无法修改成员变量age.
如果将初始化age放到构造函数中会如何呢:
/** * @author Cool-Coding 2018/5/15 */ public class ReflectionUsage {private final int age; public ReflectionUsage(){ this.age=18; } public int getAge(){ return age; } }
再执行RefectionTest会发生什么呢?会发现结果变成了68。
为什么会发生这种情形呢?看一下这两个情况下生成的class文件有什么不同:
直接初始化:
public class ReflectionUsage { private final int age = 18; public ReflectionUsage() { } public int getAge() { return 18; } }
构造函数中初始化:
public class ReflectionUsage { private final int age = 18; public ReflectionUsage() { } public int getAge() { return this.age; } }
可以看出如果直接初始化时,经过编译后getAge方法直接返回常量值,而在构造函数中初始化时,返回的是this.age变量的值。
String类型
/** * @author Cool-Coding 2018/5/15 */ public class ReflectionUsage { private final String reflectionString="reflectionString"; public String getReflectionString(){ return reflectionString; } }
测试代码:
import java.lang.reflect.Field; /** * @author Cool-Coding 2018/5/15 */ public class ReflectionTest { public static void main(String[] args){ try { Class reflectionUsage = Class.forName("practise.practise.ReflectionUsage"); ReflectionUsage o = (ReflectionUsage)reflectionUsage.newInstance(); Field reflectionString = reflectionUsage.getDeclaredField("reflectionString"); reflectionString.setAccessible(true); reflectionString.set(o,"newReflectionString"); reflectionString.setAccessible(false); System.out.println(o.getReflectionString()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); }catch (IllegalAccessException | InstantiationException e){ } } }
运行结果:reflectionString
如果将初始化reflectionString放到构造函数中又如何呢?
/** * @author Cool-Coding 2018/5/15 */ public class ReflectionUsage { private final String reflectionString; public ReflectionUsage(){ this.reflectionString="reflectionString"; } public String getReflectionString(){ return reflectionString; } }
运行结果:newReflectionString
为什么运行结果不同呢,来看下class文件:
直接初始化:
public class ReflectionUsage { private final String reflectionString = "reflectionString"; public ReflectionUsage() { } public String getReflectionString() { return "reflectionString"; } }
构造函数中初始化:
public class ReflectionUsage { private final String reflectionString = "reflectionString"; public ReflectionUsage() { } public String getReflectionString() { return this.reflectionString; } }
可以看出跟基本类型相似,直接初始化时,编译器会将reflectionString出现的地方,替换成常量值,而构造函数中初始化不替换。
Integer类型
/** * @author Cool-Coding 2018/5/15 */ public class ReflectionUsage { private final Integer age=18; public Integer getAge(){ return age; } }
测试代码:
import java.lang.reflect.Field; /** * @author Cool-Coding 2018/5/15 */ public class ReflectionTest { public static void main(String[] args){ try { Class reflectionUsage = Class.forName("practise.practise.ReflectionUsage"); ReflectionUsage o = (ReflectionUsage)reflectionUsage.newInstance(); Field reflectionString = reflectionUsage.getDeclaredField("age"); reflectionString.setAccessible(true); reflectionString.set(o,68); reflectionString.setAccessible(false); System.out.println(o.getAge()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); }catch (IllegalAccessException | InstantiationException e){ } } }
运行结果:68
可以看出直接初始化private final Integer age变量后,不像基本类型和String类型一样不能修改,原因是什么呢,看下class文件。
public class ReflectionUsage { private final Integer age = Integer.valueOf(18); public ReflectionUsage() { } public Integer getAge() { return this.age; } }
可以看到编译器并未将getAge中变量替换成常量。
看到对Integer赋值时,编译器进行了自动装箱,那如果初始化String变量时,使用String.value()方式时,能否被修改呢,来看一下。
/** * @author Cool-Coding 2018/5/15 */ public class ReflectionUsage { private final String reflectionString = String.valueOf("reflectionString"); public ReflectionUsage() { } public String getReflectionString() { return this.reflectionString; } }
运行结果:newReflectionString
可以看出,reflectionString的值被修改了,看下class文件:
package practise.practise; public class ReflectionUsage { private final String reflectionString = String.valueOf("reflectionString"); public ReflectionUsage() { } public String getReflectionString() { return this.reflectionString; } }
可见编译器并未替换getReflectionString方法中的变量。
如果在构造函数中初始化Integer类型变量呢?
public class ReflectionUsage { private final Integer age; public ReflectionUsage() { this.age=18; } public Integer getAge() { return this.age; } }
运行结果:68
age值也被改变了,看下class文件:
public class ReflectionUsage { private final Integer age = Integer.valueOf(18); public ReflectionUsage() { } public Integer getAge() { return this.age; } }
生成的class文件与直接初始化是一样的。
总结:
final可以修改类,变量,方法,表示不可继承,不可修改,不可覆盖(override),这里讨论了使用反射修改private final修饰的成员变量情况,当private final修改直接初始化的基本类型或String(注意不能使用String.valueOf()初始化)时,使用反射无法修改变量值,其它情况下可以修改。这也告诉我们在平时开发时,如果想定义常量请在基本类型int或String类型前加private final修饰,这样编译器会在编译时将这些变量出现的地方替换成常量,以免被恶意修改。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
通过下列任意一个方法访问成员变量时将返回 Field 类型的对象或数组。 getFields() getField(String name) getDeclaredFields() getDeclaredField(String name) 上述方法返回的 Field 对象代表一个成员变量。例如,要访问一个名称为 price 的成员变量,示例代码如下: Field 类的常用方法如表 1 所示 表1
主要内容:判定及获取元素的相关方法,值修改相关方法,值可修改条件之一:可被寻址,值可修改条件之一:被导出Go语言中类似 x、x.f[1] 和 *p 形式的表达式都可以表示变量,但是其它如 x + 1 和 f(2) 则不是变量。一个变量就是一个可寻址的内存空间,里面存储了一个值,并且存储的值可以通过内存地址来更新。 对于 reflect.Values 也有类似的区别。有一些 reflect.Values 是可取地址的;其它一些则不可以。考虑以下的声明语句: x := 2 // value type
- a - addr : rt_i2c_bus_device , rt_i2c_msg ai_addr : addrinfo ai_addrlen : addrinfo ai_canonname : addrinfo ai_family : addrinfo ai_flags : addrinfo ai_next : addrinfo ai_protocol : addrinfo ai_soc
使用Java反射,是否可以获取局部变量的名称?例如,如果我有: 有没有可能实现一种方法,可以找到这些变量的名称,比如: 编辑:这个问题与Java中有没有找到传递给函数的变量名称的方法不同?在这一点上,它更纯粹地询问一个人是否可以使用反射来确定局部变量的名称,而另一个问题(包括公认的答案)更侧重于测试变量的值。
这里列出了所有文档化的结构体和联合体的成员变量,并附带结构或联合所属的文件: - a - addr : rt_i2c_bus_device , rt_i2c_msg ai_addr : addrinfo ai_addrlen : addrinfo ai_canonname : addrinfo ai_family : addrinfo ai_flags : addrinfo ai_next : a
本文向大家介绍Java 反射修改类的常量值、静态变量值、属性值实例详解,包括了Java 反射修改类的常量值、静态变量值、属性值实例详解的使用技巧和注意事项,需要的朋友参考一下 前言 有的时候,我们需要修改一个变量的值,但变量也许存在于 Jar 包中或其他位置,导致我们不能从代码层面进行修改,于是我们就用到了下面的场景,通过反射来进行修改变量的值。 定义一个实体类 利用反射修改私有静态常量方法 修改