java-反射简单说明

Java反射

1. 简单介绍:

java反射机制是在运行状态中,对于一个类(class文件,字节码文件),都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。

个人理解:
1. 粗略滴讲,动态地获取类中的信息,就是反射机制。
2. 反射可以理解为对类的解剖
3. 想要对一个类进行解剖,只要获取该类的字节码文件即可。

2.具体使用:

1. 获取字节码文件对象(Class对象)的方式

  1. 通过Object类中的getClass()方法获取字节码文件。
    想要用这种方式,必须要明确具体的类并创建对象,比较麻烦。
  2. 所有数据类型都具备一个静态的属性class,可以通过XXX.class来获取对应的Class对象。
    这种方法相对简单一些,但是还是要明确具体的类,还是需要用到该类中的静态成员,还是不够扩展。
  3. 只要通过给定类的字符串名称就可以获取该类,更为扩展。
    这种方法可以通过Class类中的方法来完成。我就不卖关子,该方法就是forName,这种方法只要有名称即可,根据类名寻找指定类文件,加载进内存,并产生Class对象(字节码文件对象),更为方便,扩列性更强,即:Class.forName("className");

className格式例子(举个栗子):com.zero.web.filter.test.Test1

forName

2. 通过Class对象创建该类的实例对象
诶~,不就是获取实例对象嘛,new一个不就好了嘛,反射个锤锤。
我说大兄弟,这个构造方法要是私有了你new个锤锤啊

通常在代码设计的时候,处于某种考虑,可能会把一个类的构造函数给私有,这种情况下,我们想获取该类的实例对象就不能通过传统的new关键字来获取了,这个时候怎么办呢?这个时候我们就可以借助Class对象(上面说了怎么获取Class对象)并通过反射获取该类的实例对象。具体方法如下:

通过调用该Class对象中的newInstance()方法来创建该类的实例对象,
即 : 该字节码文件对象.newInstance();


PS:当获取指定名称对应类中的实例对象时,不能使用空参数构造函数怎么办?
既然是需要通过指定构造函数才能初始化实例对象,那么就先获取该实例对象。
方法是 : Class对象.getConstructor(Class<?>… paramterTypes);
例:

Constructor constructor = clazz.getConstrctor(String.class, int.class);
//clazz就是Class对象

然后通过该构造器对象中的newInstance方法进行对象的初始化。
例:Object ob = constructor.newInstance("小明", 38);

3. 通过Class对象获取该类的字段
直接说步骤吧:
1. 获取class对象(上面讲了,这里不重复了)


2 . 通过获取的class对象,调用它的getField()/getDeclaredField()方法,获取该类的字段

Field field = clazz.getField(“age”);只能获取公有字段
Field field = clazz.getDeclaredField(“age”);只获取本类中所有字段,包含私有字段

3.通过Class对象获取其实现类,例:Object obj = clazz.newInstance();


4.然后通过该实现类访问上一步获取到的字段。例:Object o = filed.get(obj);//变量o就是获取的字段

这里解释一下:
因为获取通过Class对象获取的字段要进行使用的话是需要访问的,但是需要访问该字段(类中的成员)数据是需要通过类来访问的,所以需要通过获取对象来进行访问,但是这还不够,因为在Java中,访问对象中的成员时会进行检查,检查该成员是否是私有成员,所以当想访问私有对象的时候我们可以使用上一步中的field对象中的方法,field.setAccessible(true);来取消java对访问权限的检查。(暴力访问)


5.后期也可以通过实现对象对取出来的字段进行修改
例:filed.set(obj, 89);


4. 通过Class对象创建该类的方法
1. 获取Class对象
例:Class clazz = Class.forName("className");
2. 通过Class对象获取该类中的方法

栗子说明
Method[] methods = clazz.getMethods();获取全部公有方法
Method[] methods = clazz.getDeclareMethods();获取该类中的全部方法,包含私有方法
Method method = clazz.getMethod("方法名","参数类型.class");获取该类中指定公有方法
Method method = clazz.getDeclaredMethod("方法名","参数类型.class");获取该类中指定方法,不论公有私有

例:

Method method = clazz.getMethod("show",null);//获取该类中指定公有方法show,该方法不带任何参数
Method method = clazz.getMethod("setAge", int.class);//获取该类中指定公有方法setAge,该方法带一个int类型的参数
  1. 通过Class对象创建该类的对象(实例),
    例:
    Object obj = clazz.newInstance();
    //或:
    Constructor constructor = clazz.getConstructor(String.class, int.class));
    Object obj = constructor.newInstance("小明", 23);
    
  2. 通过该实例对象获取调用方法
    例:
    method.invoke(obj,  null);	调用第2步例子中的show方法
    //或:
    method.invoke(obj,  23);	调用第2步例子中的setAge方法
    
### Java反射高级特性与最佳实践 #### 反射概述 Java反射机制允许程序在运行时动态地获取类的信息并对其进行操作。这包括但不限于创建对象、访问和修改字段、调用方法等功能[^1]。 #### 动态获取类信息 通过`java.lang.Class`可以实现对任意类型的自省,即查询其结构特征而不必事先知道具体的类型名称。例如: ```java // 获取Class实例的方式之一:已知对象的情况下 Object obj = new String(); Class<?> clazz = obj.getClass(); // 或者直接指定类型名来获得对应的Class对象 Class<String> stringClass = String.class; ``` #### 字段访问与设置 能够读取或更改私有属性的值是一项强大的功能,在某些情况下非常有用,比如单元测试或者ORM框架内部逻辑实现中。下面是一个简单的例子展示如何做到这一点: ```java Field privateStringField = MyClass.getDeclaredField("privateFieldName"); privateStringField.setAccessible(true); // 打开权限以便后续操作 privateStringField.set(myInstance, "new value"); // 设置新值给该字段 ``` #### 方法调用 除了基本的数据成员外,还可以借助于`Method`类来进行函数级别的交互。这里给出一段示范代码片段用于说明怎样执行静态方法以及带参数的方法调用过程: ```java // 调用无参构造器创建新的实例 Constructor<MyClass> constructor = myClass.getConstructor(); MyClass instance = constructor.newInstance(); // 查找特定签名的方法定义 Method methodWithArgs = myClass.getMethod("methodName", int.class); methodWithArgs.invoke(instance, 42); // 带有一个整数参数的方法调用 ``` #### 泛型支持下的反射运用 当涉及到带有泛型声明的对象时,则需要额外注意一些细节问题。因为擦除机制的存在使得编译后的字节码丢失了大部分有关泛型的具体信息。不过仍然可以通过TypeToken等方式绕过这些限制从而更好地兼容各种复杂情况[^2]。 #### 安全性和性能考量 虽然反射带来了极大的灵活性,但也伴随着一定的代价——它可能会降低应用程序的整体效率,并且如果滥用的话还可能引发安全隐患。因此建议仅限于确实必要的场合下才考虑采用此技术手段;同时遵循官方文档推荐的做法以减少潜在的风险因素[^3]。 #### 实际应用场景举例 - **AOP编程**: 利用拦截器模式增强目标行为之前/之后的行为。 - **依赖注入容器(DI/IoC)**: 自动装配组件之间的协作关系。 - **JSON/XML解析库**: 将外部格式转换成内存表示形式。 - **数据库持久层工具(ORM)**: 映射实体到表记录之间相互转化的过程。 #### 类卸载的重要性 对于那些频繁加载不同版本的第三方模块或是基于插件架构构建的产品来说,确保及时释放不再使用的资源至关重要。尤其是在JVM配置不当的时候容易遇到PermGen space不足的问题,此时开启-Xnoclassgc选项可以帮助缓解此类状况的发生频率[^4]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值