首页 > 其他分享 >【反射】反射获取私有字段小记

【反射】反射获取私有字段小记

时间:2023-12-29 14:01:56浏览次数:27  
标签:Field 反射 java 获取 私有 对象 字段 实例 小记

问题:

// 直接按类字面量获取
Class<?> myClass = ClassTestA.class;
// 全类名反射获取
Class<?> myClass = Class.forName("com.cambrianwenjie.demo.ClassTestA");

// 获取私有字段
Field privateField = myClass.getDeclaredField("name");

// 设置私有字段可访问
privateField.setAccessible(true);

// 获取并修改私有字段的值
String fieldValue = (String) privateField.get(myClass);

以上代码在运行到获取并修改私有字段的值时,会提示

Exception in thread  "main" java.lang.IllegalArgumentException: Can not set java.lang.String field com.cambrianwenjie.demo.ClassTestA.name to java.lang.Class
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java: 167 )
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java: 171 )
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java: 58 )
    at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java: 36 )
    at java.lang.reflect.Field.get(Field.java: 393 )

 

疑惑:

forName获取到的就是类的全部信息,包括字段(Field)的信息。通过Class对象可以调用Field类中的get方法来获取字段的值,那么为什么会报错?

查看Field的get()方法的JavaDoc

 

大概翻译一下:

  • 返回由该Field对象表示的字段在指定对象上的值。如果字段具有原始类型,则该值会自动包装为对象。
  • 获取底层字段的值的方式如下:
    • 如果底层字段是静态字段,则忽略obj参数;它可以为null。
    • 否则,底层字段是实例字段。如果指定的obj参数为null,则该方法抛出NullPointerException异常。如果指定的对象不是声明底层字段的类或接口的实例,则该方法抛出IllegalArgumentException异常
  • 如果Field对象正在强制执行Java语言的访问控制,并且底层字段不可访问,则该方法抛出IllegalAccessException异常。如果底层字段是静态字段,并且尚未初始化声明该字段的类,则会初始化该类。
  • 否则,从底层实例或静态字段中检索值。如果字段具有原始类型,则在返回之前将该值包装在对象中,否则按原样返回。
  • 如果字段在obj的类型中被隐藏,则根据前面的规则获取字段的值。

问题原因:

关键就在于上面加粗斜体的部分,更关键的是加粗斜体部分的红字

 

类的字面量和全类名反射获取的Class都是类对象而非类的实例对象

此处解释下类对象和类的实例对象:

  1. 定义:

    • 类对象(Class Object):表示整个类的定义,包括类的结构、方法、字段等信息。在Java中,类对象是在运行时由Java虚拟机(JVM)动态创建和管理的。
    • 类的实例对象(Instance Object):表示类的一个具体实例,是类对象的一个实例化对象。在Java中,类的实例对象是通过使用new关键字或其他创建对象的方式创建的。
  2. 内容:

    • 类对象:包含了类的定义和结构信息,例如类的方法、字段、构造函数、静态代码块等。类对象在内存中只有一份,对于一个类而言,类对象是唯一的。
    • 类的实例对象:表示类的一个具体实例,每个实例都有自己的独特状态和数据。每次创建类的实例对象时,都会在内存中分配一块新的内存空间来存储实例的数据。
  3. 访问:

    • 类对象:可以通过类字面量(例如ClassName.class)或Class.forName()方法来获取类对象。通过类对象可以获取类的各种信息,如方法、字段、注解等。
    • 类的实例对象:通过创建对象的方式,使用new关键字或其他创建对象的方式来获取类的实例对象。通过实例对象可以访问和操作实例的成员变量和方法。
  4. 功能:

    • 类对象:用于获取类的结构信息,进行反射操作,如动态创建对象、调用方法、访问字段等。
    • 类的实例对象:用于表示类的一个具体实例,可以通过实例对象来访问和操作实例的成员变量和方法。

总的来说,类对象是类的定义和结构信息的表示,而类的实例对象是类的具体实例,每个实例有自己的状态和数据。类对象用于操作和获取类的结构信息,而类的实例对象用于访问和操作实例的成员变量和方法。

因此如果要调用Field的get()方法,需要传入一个实例化对象才可以。

比如将上述代码最后一个行改为:

// 获取并修改私有字段的值
String fieldValue = (String) privateField.get(myClass.newInstance());

 

标签:Field,反射,java,获取,私有,对象,字段,实例,小记
From: https://www.cnblogs.com/onejay/p/17934706.html

相关文章

  • Java反射,看完就会用
    什么是反射在说反射概念之前,我们先说另外2个概念:编译期和运行期。编译期:编译期是源代码从文本形式转换为字节码的过程,这发生在Java代码被JVM执行之前。在编译期,编译器对源代码进行语法检查、类型检查、变量名解析等操作,确保代码符合Java的语法规则,并将其编译成字节码(.class文......
  • Java反射
    一、获取Class对象1、调用运行时类的.class属性ClassstuClass=Student.class;2、调用运行时类的getClass方法Students=newStudent();ClassstuClass=s.getClass();3、调用Class类的静态方法:forName(StringclassPath)【该种方法用的多】ClassstuClass=Clas......
  • 【类型转换】使用c#实现简易的类型转换(Emit,Expression,反射)
    引言哈喽。大家好,好久不见,最近遇到了一个场景,就是在FrameWork的asp.netmvc中,有个系统里面使用的是EntityFramework的框架,在这个框架里,提供了一个SqlQuery的方法,这个方法很好用啊,以至于在EFCORE8里面又添加了回来,不过不知道性能怎么样,我遇到的场景是通过SqlQuery查询的时......
  • 十九,反射
    //断言模式:10+10=30@TestpublicvoidtestAdd(){  Assert.assertEquals(20,newJiSuanQi().add(10,10));}  @Ignore//忽略该函数  @Test(timeout=3000)//单位:毫秒  publicvoidtestRun(){    //while(true){    //  ......
  • 如何在华为云欧拉系统 ECS 实例新建私有 REPO 源并制作安全 RPM 包
    写在前面工作中遇到,简单整理博文内容为华为云开发者认证实验笔记理解不足小伙伴帮忙指正对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是对大众理想的懦弱回归,是随波逐流,是对内心的恐惧——赫尔曼·......
  • 反射
    公共函数的调用Class<A>clazz=A.class;通过反射创建对象获取函数对象try{Methodmethod=clazz.getMethod("m1");//形参类型Objecto=clazz.newInstance();//JDK9中过时了调用空参函数Objectinvoke=method.invoke(o);//实参System.out.println("invo......
  • Java反射
    一、反射的概述JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。要想解剖一个类,必须先要获取到该类的字节码文件对象。而解......
  • 私有云 SDK 集成后数据库加密、解密失败、崩溃
    问题原因私有云IMLib提供了数据库加密功能,并且其中包含了一份sqlite3的源码,所以使用私有云IM库的项目中就不能再引入其它sqlite库了,引用系统的或者手动加入的都可能会造成异常解决方案在Xcode中查看对应TARGETS的BuildPhases→LinkBinaryWithLibraries下是否有......
  • 无涯教程-Java9 - 私有接口方法
    在Java8之前,接口可以具有以下类型的变量/方法。Constantvariables(常量)Abstractmethods  (抽象方法)因此,无涯教程不能在接口中实现方法实现,或更确切地说,不能在Java8之前拥有默认实现。请参见示例。publicclassTester{publicstaticvoidmain(String[]args)......
  • 深入探讨Java反射:解析机制与应用场景
    当谈及Java编程语言的强大功能时,反射(Reflection)是一个不可忽视的特性。反射允许程序在运行时检查和操作其自身的结构,这为开发者提供了一种动态获取信息和执行操作的途径。在本篇博客中,我们将深入探讨Java反射的原理、用法以及一些实际场景中的应用。什么是反射?反射是Java的一种......