Java中反射的定义及应用

思考:

Java里main方法执行程序,但是servlet里没有main方法是如何执行的?——通过反射方式执行

反射的定义

反射(Reflection)是 Java 的一种特性,它可以让程序在运行时获取自身的信息,并且动态地操作类或对象的属性、方法和构造器等。通过反射功能,可以让我们在不知道具体类名的情况下,依然能够实例化对象,调用方法以及设置属性。

简而言之,反射是获取类信息的一种能力。

什么是类信息?  

在一个类中有方法 变量 构造器 继承和实现的类或接口,这些为类信息。

反射的核心概念

反射的核心是java.lang.reflect包,主要涉及以下类:

  1. Class类:代表一个类或接口

  2. Field类:代表类的成员变量

  3. Method类:代表类的方法

  4. Constructor类:代表类的构造方法 

反射的应用

反射使用步骤:

1.生成类对象(3种方式)

2.获取类信息,类信息的存储形式有2种:获取相关集合、直接获取

一、获取类对象

1、通过类名.class获取

Class<String> stringClass = String.class;

2、 通过对象.getClass()获取

String str = "Hello";
Class<?> strClass = str.getClass();

3、 通过Class.forName()获取(最常用)

Class<?> arrayListClass = Class.forName("java.util.ArrayList");

3种方式对应三个阶段

public class CatTest {
	public static void main(String[] args) throws Exception{
        //方式1
		Class clazz1=Class.forName("com.qc.May.Cat");
		//方式2
		Class clazz2=Cat.class;
		//方式3
		Cat cat=new Cat("黑色");
		Class clazz3=cat.getClass();
		//测试是否指向同一块内存空间,结果为true
		System.out.println(clazz1==clazz2);
		System.out.println(clazz2==clazz3);
	}
	
}

二、获取类信息

反射获取变量 Field

Class<?> clazz = Class.forName("com.example.Person");

// 获取public字段(包括父类的public字段)
Field publicField = clazz.getField("fieldName");

// 获取本类声明的所有字段(包括private,不包括父类的)
Field privateField = clazz.getDeclaredField("fieldName");

// 获取所有public字段
Field[] publicFields = clazz.getFields();

// 获取本类所有字段(包括private)
Field[] allFields = clazz.getDeclaredFields();

反射获取方法  Method

//getDeclaredMethods()获取全部方法
Method[] methods=clazz.getDeclaredMethods();

//getMethods()只能获取public方法
Method[] methods2=clazz.getMethods();
		
// 获取公共方法(包括继承的)
Method method = clazz.getMethod("方法名", 参数类型.class, ...);

// 获取所有方法(包括私有方法,不包括继承的)
Method privateMethod = clazz.getDeclaredMethod("方法名", 参数类型.class, ...);

// 调用方法
Object result = method.invoke(实例对象, 参数值1, 参数值2, ...);

// 调用私有方法需要先设置可访问
privateMethod.setAccessible(true);
Object result = privateMethod.invoke(实例对象, 参数值...);

反射获取构造器 Constructor

// 1. 获取类中所有的公共(public)构造方法(不包括父类的构造方法)
Constructor[] constructors0 = clazz.getConstructors();

// 2. 获取类中声明的所有构造方法(包括private、protected、default、public)
Constructor[] constructors1 = clazz.getDeclaredConstructors();

// 3. 获取类中特定的无参构造方法(可以是任意访问权限)
// 如果找不到匹配的构造方法会抛出NoSuchMethodException
// 注意:即使构造方法是private的,也能获取到,但调用前需要setAccessible(true)
Constructor constructor2 = clazz.getDeclaredConstructor();

// 4. 获取类中特定的有参构造方法(参数类型为String,可以是任意访问权限)
Constructor constructor3 = clazz.getDeclaredConstructor(String.class);

输出结果 

[public com.qc.May.Cat(int,java.lang.String,java.lang.String,double)]
[public com.qc.May.Cat(int,java.lang.String,java.lang.String,double)]
[Ljava.lang.reflect.Constructor;@15db9742
com.qc.May.Cat(java.lang.String)

反射获取接口 

Class[] classes=clazz.getInterfaces();

关于构造器

构造器其实是创建类对象的;

类本身有一个未显示的无参构造器,当在类里写构造器时,默认构造器被覆盖;

三、操作类信息

变量的基本操作

获取变量值 

Object obj = clazz.newInstance();
Field field = clazz.getDeclaredField("age");

// 对于public字段可以直接获取
int age = (int) field.get(obj);

// 对于private字段需要先设置可访问
field.setAccessible(true); // 突破private限制
int age = (int) field.get(obj);

设置变量值

Object obj = clazz.newInstance();
Field field = clazz.getDeclaredField("name");

// 设置public字段
field.set(obj, "张三");

// 设置private字段
field.setAccessible(true);
field.set(obj, "李四");
方法的调用

基本调用

Object obj = clazz.newInstance();
Method method = clazz.getMethod("sayHello", String.class);

// 调用方法
Object result = method.invoke(obj, "张三");

调用静态方法

Method staticMethod = clazz.getMethod("staticMethod", String.class);

// 静态方法调用时,obj参数传null
Object result = staticMethod.invoke(null, "参数");

调用私有方法 

Method privateMethod = clazz.getDeclaredMethod("privateMethod");

// 突破private限制
privateMethod.setAccessible(true);

Object result = privateMethod.invoke(obj);

方法信息获取

Method method = clazz.getMethod("toString");

// 获取方法名
String methodName = method.getName();

// 获取返回类型
Class<?> returnType = method.getReturnType();

// 获取参数类型数组
Class<?>[] paramTypes = method.getParameterTypes();

// 获取异常类型数组
Class<?>[] exceptionTypes = method.getExceptionTypes();

// 获取修饰符
int modifiers = method.getModifiers();
boolean isPublic = Modifier.isPublic(modifiers);
boolean isStatic = Modifier.isStatic(modifiers);

反射的优缺点

优点:

  • 极大的灵活性

  • 可以在运行时动态操作类和对象

  • 适合开发通用框架和工具

缺点:

  • 性能开销大(比直接调用慢)

  • 破坏封装性(可以访问私有成员)

  • 增加代码复杂度

  • 绕过泛型检查

  • 安全问题(可以调用任意方法)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值