当前位置: 首页 > article >正文

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 的高级特性。在使用反射时,需要注意性能问题、安全限制和异常处理,以确保程序的正确性和稳定性。

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

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


http://www.kler.cn/a/280346.html

相关文章:

  • cookie, session and token
  • Python脚本阿里云服务监控脚本
  • 93.WEB渗透测试-信息收集-Google语法(7)
  • 【YOLO系列】目标检测简介
  • 谈到这个痛点,写C的和不写C的码农都沉默了
  • Unity项目增加字体裁剪
  • spingboot实现常规增删改查
  • 如何使用ssm实现亿互游在线平台设计与开发+vue
  • QT opencv(显示图片和视频)
  • 电脑浏览器打不开部分网页
  • ARP(地址解析协议)详解
  • mysql数据库----简单认识库的操作
  • 什么是死锁
  • 大模型从入门到精通—— LLM 应用评估(二)
  • 【C++ 面试 - 面向对象】每日 3 题(七)
  • RabbitMQ中的死信交换机?(RabbitMQ延迟队列有了解过吗)
  • 中庸就是五五开,各打五十大板吗
  • 8.28-回顾+容器与主机之间的通信+跨主机容器之间的通信
  • 如何监控Eureka集群:Prometheus与Grafana的监控集成
  • 音频分割软件有什么?最方便的音频分割软件分享给你