Java核心技术【二十六】Java 反射详解(基于 JDK 17)

在 Java 编程中,反射是一种强大的机制,它允许程序在运行时动态地获取类的信息、访问对象的属性和方法、创建对象等。对于初学者来说,理解反射可能会有一定的挑战,但它也是掌握 Java 高级特性的重要一步。

一、什么是反射

反射(Reflection)是指在程序运行时,能够获取一个对象所属的类信息,包括类的名称、属性、方法、构造函数等,并且可以通过这些信息来操作对象。简单来说,反射就是让程序能够 “自我审视” 和 “自我操作”。

二、反射的作用

1. 动态创建对象

在某些情况下,我们可能不知道要创建的对象的具体类型,只知道类的名称。通过反射,可以根据类名动态地创建对象。

2. 访问和修改对象的属性

反射可以让我们在运行时访问和修改对象的私有属性,这在一些需要动态配置的场景中非常有用。

3. 调用对象的方法

可以根据方法名和参数类型在运行时调用对象的方法,而不需要在编译时就确定方法的调用。

三、反射的基本用法

(一)获取类对象

首先,定义一个测试类 MyClass

package java_core_26;


public class MyClass{
	
	private static final long serialVersionUID = 1L;
	private String name = "小明";
	private String addr = "北京";
	
	public String getAll(String all) {
		return all + name;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getAddr() {
		return addr;
	}
	public void setAddr(String addr) {
		this.addr = addr;
	}
	public MyClass(String name, String addr) {
		super();
		this.name = name;
		this.addr = addr;
	}
	public MyClass() {
		super();
		// TODO Auto-generated constructor stub
	}
	
}

在 Jdk 17 中,要使用反射,首先需要获取一个类的对象。有三种方式可以获取类对象:

1. 使用类名.class

这种方式在编译时就确定了类的类型,比较安全:

   Class<?> clazz = MyClass.class;

2. 使用对象的 getClass () 方法

这种方式通过已经创建的对象来获取类对象:

   MyClass obj = new MyClass();
   Class<?> clazz = obj.getClass();

3. 使用 Class.forName () 方法

这种方式需要传入类的全限定名,在运行时加载类。如果类找不到,会抛出 ClassNotFoundException

   try {
       Class<?> clazz = Class.forName("java_core_26.MyClass");
   } catch (ClassNotFoundException e) {
       e.printStackTrace();
   }	   

(二)创建对象

获取了类对象之后,可以通过反射来创建对象。在 JDK 17 使用 getConstructor() 方法获取无参构造函数,然后通过构造函数的 newInstance() 方法创建对象。如果类没有无参构造函数,或者构造函数不可访问,会抛出相应的异常。

public class Test {
	
	public static void main(String[] args) {
		
		try {
		    Class<?> clazz = Class.forName("java_core_26.MyClass");
		    // 获取无参构造函数
		    var constructor = clazz.getConstructor();
		    // 使用构造函数创建对象
		    Object obj = constructor.newInstance();
		    
		} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
		    e.printStackTrace();
		}
		   
	}
}

(三)访问属性

反射可以让我们访问对象的私有属性。在 JDK 17 中,可以使用以下方式访问属性:

public class Test {
	
	public static void main(String[] args) {
		
		try {
		    Class<?> clazz = Class.forName("java_core_26.MyClass");
		    // 获取无参构造函数
		    var constructor = clazz.getConstructor();
		    // 使用构造函数创建对象
		    Object obj = constructor.newInstance();
		    // 获取私有属性 addr
		    Field field = clazz.getDeclaredField("addr");
		    // 允许访问私有属性
		    field.setAccessible(true);
		    // 设置属性值
		    field.set(obj, "new value");
		    // 获取属性值
		    Object value = field.get(obj);
		    System.out.println(value);
		    
		} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | 
				IllegalAccessException | InvocationTargetException | NoSuchFieldException | 
				SecurityException e) {
		    e.printStackTrace();
		}
		   
	}
}	

在上面的代码中,getDeclaredField() 方法获取 MyClass 的私有属性 addrsetAccessible(true) 设置属性可访问,然后通过 set()get() 方法设置和获取属性的值。

(四)调用方法

反射也可以用来调用对象的方法。在 JDK 17 中,可以使用以下方式调用方法:

package java_core_26;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class Test {
	
	public static void main(String[] args) {
		
		try {
			 Class<?> clazz = Class.forName("java_core_26.MyClass");
			    // 获取无参构造函数
			    var constructor = clazz.getConstructor();
			    // 使用构造函数创建对象
			    Object obj = constructor.newInstance();
			    // 获取方法
			    var method = clazz.getMethod("getAll", String.class);
			    // 调用方法
			    Object result = method.invoke(obj, "小李");
			    System.out.println(result);
		    
		} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | 
				IllegalAccessException | InvocationTargetException | 
				SecurityException e) {
		    e.printStackTrace();
		}
		   
	}
}	

在上面的代码中,getMethod() 方法获取公共方法,传入方法名和参数类型。然后通过 invoke() 方法调用方法,传入对象和参数。如果方法有返回值,可以获取返回值。

四、反射的注意事项

1. 性能问题

反射的性能相对较低,因为它需要在运行时进行类型检查和方法调用。在性能敏感的代码中,应尽量避免频繁使用反射。

2. 安全限制

反射可以访问和修改私有属性和方法,但这可能会破坏封装性。在某些安全敏感的环境中,可能需要限制反射的使用。

3. 异常处理

使用反射时,可能会抛出各种异常,如 ClassNotFoundExceptionNoSuchMethodExceptionInstantiationExceptionIllegalAccessExceptionInvocationTargetException 等。在代码中需要进行适当的异常处理,以确保程序的稳定性。

五、总结

反射是 Java 中一种强大的机制,它允许程序在运行时动态地获取类的信息、访问对象的属性和方法、创建对象等。在 JDK 17 中,反射的基本用法与之前版本类似,但也有一些细微的变化。对于初学者来说,理解反射的基本概念和用法,可以帮助更好地理解 Java 的高级特性。在使用反射时,需要注意性能问题、安全限制和异常处理,以确保程序的正确性和稳定性。

遇见即是缘分,关注🌟、点赞👍、收藏📚,让这份美好延续下去!

🌟 对技术管理感兴趣 请关注 ⬇ 【 技术管理修行】

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值