Java反射机制详解(由浅入深)

System.out.println(“类的名称:” + mClass.getName());

//2.1 获取所有 public 访问权限的方法

//包括自己声明和从父类继承的

Method[] mMethods = mClass.getMethods();

//2.2 获取所有本类的的方法(不问访问权限)

//Method[] mMethods = mClass.getDeclaredMethods();

//3.遍历所有方法

for (Method method :

mMethods) {

//获取并输出方法的访问权限(Modifiers:修饰符)

int modifiers = method.getModifiers();

System.out.print(Modifier.toString(modifiers) + " ");

//获取并输出方法的返回值类型

Class returnType = method.getReturnType();

System.out.print(returnType.getName() + " "

  • method.getName() + "( ");

//获取并输出方法的所有参数

Parameter[] parameters = method.getParameters();

for (Parameter parameter:

parameters) {

System.out.print(parameter.getType().getName()

  • " " + parameter.getName() + “,”);

}

//获取并输出方法抛出的异常

Class[] exceptionTypes = method.getExceptionTypes();

if (exceptionTypes.length == 0){

System.out.println(" )");

}

else {

for (Class c : exceptionTypes) {

System.out.println(" ) throws "

  • c.getName());

}

}

}

}

同获取变量信息一样,需要注意注释中 2.1 与 2.2 的区别,下面看一下打印输出:

  • 调用 getMethods() 方法

获取 SonClass 类所有 public 访问权限的方法,包括从父类继承的。打印信息中,printSonMsg() 方法来自 SonClass 类, printFatherMsg() 来自 FatherClass 类,其余方法来自 Object 类。

类的名称:obj.SonClass

public void printSonMsg( )

public void printFatherMsg( )

public final void wait( ) throws java.lang.InterruptedException

public final void wait( long arg0,int arg1, ) throws java.lang.InterruptedException

public final native void wait( long arg0, ) throws java.lang.InterruptedException

public boolean equals( java.lang.Object arg0, )

public java.lang.String toString( )

public native int hashCode( )

public final native java.lang.Class getClass( )

public final native void notify( )

public final native void notifyAll( )

  • 调用 getDeclaredMethods() 方法

打印信息中,输出的都是 SonClass 类的方法,不问访问权限。

类的名称:obj.SonClass

private int getSonAge( )

private void setSonAge( int arg0, )

public void printSonMsg( )

private void setSonName( java.lang.String arg0, )

private java.lang.String getSonName( )

三、访问或操作类的私有变量和方法

================

在上面,我们成功获取了类的变量和方法信息,验证了在运行时 动态的获取信息 的观点。那么,仅仅是获取信息吗?我们接着往后看。

都知道,对象是无法访问或操作类的私有变量和方法的,但是,通过反射,我们就可以做到。没错,反射可以做到!下面,让我们一起探讨如何利用反射访问 类对象的私有方法 以及修改 私有变量或常量

老规矩,先上测试类。

注:

  1. 请注意看测试类中变量和方法的修饰符(访问权限);

  2. 测试类仅供测试,不提倡实际开发时这么写 : )

TestClass.java

3.1 访问私有方法


以访问 TestClass 类中的私有方法 privateMethod(...) 为例,方法加参数是为了考虑最全的情况,很贴心有木有?先贴代码,看注释,最后我会重点解释部分代码。

/**

  • 访问对象的私有方法

  • 为简洁代码,在方法上抛出总的异常,实际开发别这样

*/

private static void getPrivateMethod() throws Exception{

//1. 获取 Class 类实例

TestClass testClass = new TestClass();

Class mClass = testClass.getClass();

//2. 获取私有方法

//第一个参数为要获取的私有方法的名称

//第二个为要获取方法的参数的类型,参数为 Class…,没有参数就是null

//方法参数也可这么写 :new Class[]{String.class , int.class}

Method privateMethod =

mClass.getDeclaredMethod(“privateMethod”, String.class, int.class);

//3. 开始操作方法

if (privateMethod != null) {

//获取私有方法的访问权

//只是获取访问权,并不是修改实际权限

privateMethod.setAccessible(true);

//使用 invoke 反射调用私有方法

//privateMethod 是获取到的私有方法

//testClass 要操作的对象

//后面两个参数传实参

privateMethod.invoke(testClass, "Java Reflect ", 666);

}

}

需要注意的是,第3步中的 setAccessible(true) 方法,是获取私有方法的访问权限,如果不加会报异常 IllegalAccessException,因为当前方法访问权限是“private”的,如下:

java.lang.IllegalAccessException: Class MainClass can not access a member of class obj.TestClass with modifiers “private”

正常运行后,打印如下,调用私有方法成功:

Java Reflect 666

3.2 修改私有变量


以修改 TestClass 类中的私有变量 MSG 为例,其初始值为 “Original” ,我们要修改为 “Modified”。老规矩,先上代码看注释。

/**

  • 修改对象私有变量的值

  • 为简洁代码,在方法上抛出总的异常

*/

private static void modifyPrivateFiled() throws Exception {

//1. 获取 Class 类实例

TestClass testClass = new TestClass();

Class mClass = testClass.getClass();

//2. 获取私有变量

Field privateField = mClass.getDeclaredField(“MSG”);

//3. 操作私有变量

if (privateField != null) {

//获取私有变量的访问权

privateField.setAccessible(true);

//修改私有变量,并输出以测试

System.out.println("Before Modify:MSG = " + testClass.getMsg());

//调用 set(object , value) 修改变量的值

//privateField 是获取到的私有变量

//testClass 要操作的对象

//“Modified” 为要修改成的值

privateField.set(testClass, “Modified”);

System.out.println("After Modify:MSG = " + testClass.getMsg());

}

}

此处代码和访问私有方法的逻辑差不多,就不再赘述,从输出信息看出 修改私有变量 成功:

Before Modify:MSG = Original

After Modify:MSG = Modified

3.3 修改私有常量


在 3.2 中,我们介绍了如何修改私有 变量,现在来说说如何修改私有 常量

01. 真的能修改吗?

常量是指使用 final 修饰符修饰的成员属性,与变量的区别就在于有无 final 关键字修饰。在说之前,先补充一个知识点。

Java 虚拟机(JVM)在编译 .java 文件得到 .class 文件时,会优化我们的代码以提升效率。其中一个优化就是:JVM 在编译阶段会把引用常量的代码替换成具体的常量值,如下所示(部分代码)。

编译前的 .java 文件:

//注意是 String 类型的值

private final String FINAL_VALUE = “hello”;

if(FINAL_VALUE.equals(“world”)){

//do something

}

编译后得到的 .class 文件(当然,编译后是没有注释的):

private final String FINAL_VALUE = “hello”;

//替换为"hello"

if(“hello”.equals(“world”)){

//do something

}

但是,并不是所有常量都会优化。经测试对于 int 、long 、boolean 以及 String 这些基本类型 JVM 会优化,而对于 Integer 、Long 、Boolean 这种包装类型,或者其他诸如 DateObject 类型则不会被优化。

总结来说:对于基本类型的静态常量,JVM 在编译阶段会把引用此常量的代码替换成具体的常量值

这么说来,在实际开发中,如果我们想修改某个类的常量值,恰好那个常量是基本类型的,岂不是无能为力了?反正我个人认为除非修改源码,否则真没办法!

这里所谓的无能为力是指:我们在程序运行时刻依然可以使用反射修改常量的值(后面会代码验证),但是 JVM 在编译阶段得到的 .class 文件已经将常量优化为具体的值,在运行阶段就直接使用具体的值了,所以即使修改了常量的值也已经毫无意义了

下面我们验证这一点,在测试类 TestClass 类中添加如下代码:

接下来,是修改常量的值,先上代码,请仔细看注释:

/**

  • 修改对象私有常量的值

  • 为简洁代码,在方法上抛出总的异常,实际开发别这样

*/

private static void modifyFinalFiled() throws Exception {

//1. 获取 Class 类实例

TestClass testClass = new TestClass();
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

金三银四到了,送上一个小福利!

image.png

image.png

专题+大厂.jpg
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
正体系化!**

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

金三银四到了,送上一个小福利!

[外链图片转存中…(img-DiIbxkvk-1711985355565)]

[外链图片转存中…(img-SNXV2V6l-1711985355565)]

[外链图片转存中…(img-zKiAdW7V-1711985355566)]
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java反射机制是指在运行时动态地获取一个类的信息,并可以操作类的属性、方法和构造器等。Java反射机制可以使程序员在运行时动态地调用类的方法和属性,扩展类的功能,并可以实现注解、工厂模式以及框架开发等。 Java反射机制的原理如下:首先,Java编译器将Java源代码编译为字节码文件,字节码文件中包含着类的信息,这些信息包括类的名称、方法、属性和构造器等等。接着,Java虚拟机将字节码文件加载到内存中,然后通过类加载器将类加载到内存中形成一个类对象,这个类对象可以操作字节码文件中的信息。 使用Java反射机制的过程如下:首先获取类对象,通过类对象来获取类的构造器、属性、方法等信息,然后调用构造器来创建对象,通过属性获取和设置类的成员属性,通过方法调用类的方法等。 Java反射机制的优点是可以在运行时动态地得到类的信息,使得程序员在程序运行时能够对类进行更加灵活的操作,并可以使得程序更加通用化,同时也存在着一定的性能问题,因为Java反射机制需要Java虚拟机进行一定的额外处理,所以在程序运行时需要进行额外的时间和资源消耗。 总之,Java反射机制Java语言的一项重要特性,在Java开发中广泛应用,在代码编写、框架开发以及API开发中具有重要作用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值