Java反射如何修改private final成员变量值

大家都知道使用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修饰,这样编译器会在编译时将这些变量出现的地方替换成常量,以免被恶意修改。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 反射调用private方法实践(php、java)

    单测中有个普遍性的问题,被侧类中的private方法无法直接调用.小拽在处理过程中通过反射改变方法权限,进行单测,分享一下,直接上代码. 简单被测试类 生成一个简单的被测试类,只有个private方法. 复制代码 代码如下: <?php/** * 崔小涣单测的基本模板. * * @author cuihuan * @date 2015/11/12 22:15:31 * @version $Revision:1.0$ **/class MyClass {/** * 私有方法 * * @param

  • java中利用反射调用另一类的private方法的简单实例

    我们知道,Java应用程序不能访问持久化类的private方法,但Hibernate没有这个限制,它能够访问各种级别的方法,如private, default, protected, public. Hibernate是如何实现该功能的呢?答案是利用JAVA的反射机制,如下: import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflectDemo {

  • 利用反射获取Java类中的静态变量名及变量值的简单实例

    JAVA可以通过反射获取成员变量和静态变量的名称,局部变量就不太可能拿到了. public class Test { public static void main(String[] args) throws Exception { // TODO Auto-generated method stub //获取所有变量的值 Class clazz = Class.forName("com.qianmingxs.ScoreTable"); Field[] fields = clazz.g

  • java反射_改变private中的变量及方法的简单实例

    java反射_改变private中的变量及方法的简单实例 class DemoTest{ private String name="123"; public getName(){ system.out.println("public getName " + name); return name; } private getName2(){ system.out.println("private getName2 " + name); return

  • Java反射如何修改private final成员变量值

    大家都知道使用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.refl

  • Java 反射修改类的常量值、静态变量值、属性值实例详解

    前言 有的时候,我们需要修改一个变量的值,但变量也许存在于 Jar 包中或其他位置,导致我们不能从代码层面进行修改,于是我们就用到了下面的场景,通过反射来进行修改变量的值. 定义一个实体类 class Bean{ private static final Integer INT_VALUE = 100; } 利用反射修改私有静态常量方法 System.out.println(Bean.INT_VALUE); Field field = Bean.class.getField("INT_VALUE

  • Java反射如何获取字段属性值

    目录 Java反射获取字段属性值 案例 反射对象获取属性和值凭借成string 描述 直接上代码 Java反射获取字段属性值 反射获取Java类的所有字段,包括所有父类中的字段. 类自身的字段可直接通过方法 getDeclaredFields()[获取所有修饰符字段]或者getFields()[获取public修饰的字段]获取, 但父类中的字段暂时没有发现直接获取的方式. 需要递归获取所有的父类, 然后获取他们的字段, 最终获取到类的所有字段. 如果要获取字段值, 则需要设置字段可访问即:fie

  • Java反射如何有效的修改final属性值详解

    前言 以前写过一篇 Java 反射修改 final 属性值,本文将在这里重新温习一下Java反射如何有效的修改final属性值,下面话不多说了,来一起看看详细的介绍: 假设有个类 class Person { public final String name = "Mike"; } 这里声明 name 为非静态的属性只是为了说明反射修改 final 属性无关乎静态不静态,静态只是表现在它是一个类属性,在一个类加载器空间只会有一份拷贝,仅此而已. 创建一个通用方法进行反射修改属性值 pu

  • Java修改Integer变量值遇到的问题及解决

    目录 Java 修改Integer变量值 下面我尝试了两种方法去改变Integer的整型值 看看源码 Integer值比较需要注意的问题 原因 解决办法 Java 修改Integer变量值 对于Integer变量来说,比较变量值常见情形如下: Integer a = 1000; Integer b = 1000; Integer c = 100; Integer d = 100; System.out.println(a == b); System.out.println(c == d); "=

  • 如何利用反射批量修改java类某一属性的代码详解

    下面看下代码,具体代码如下所示: package utils.copyProperty; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; public class CopyProperty { public static Pro

  • Java反射 Field类的使用全方位解析

    Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限.反射的字段可能是一个类(静态)字段或实例字段. Field 成员变量的介绍 每个成员变量有类型和值. java.lang.reflect.Field 为我们提供了获取当前对象的成员变量的类型,和重新设值的方法. 获取变量的类型 类中的变量分为两种类型:基本类型和引用类型: 基本类型( 8 种) 整数:byte, short, int, long 浮点数:float, double 字符:char 布尔值:boolean 引用类

  • Java反射机制概念、原理与用法总结

    本文实例讲述了Java反射机制概念.原理与用法.分享给大家供大家参考,具体如下: 反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 反射机制能做什么 反射机制主要提供了以下功能: ① 在运行时判断任意一个对象所属的类: ② 在运行时构造任意一个类的对象: ③ 在运行时判断任意一个类所具有的成员变量和方法: ④ 在运行时调用任意一个

随机推荐