Java反射机制

本文介绍如何使用Java反射机制创建带参数的对象实例,并演示了通过反射复制对象的过程,同时提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、案例

1. 运行时利用带参构造方法生成类实例

利用Constructor的newInstance()方法,首先准备一个Class[]数组作为Constructor的参数类型,然后调用Class对象的getConstructor()方法获得一个专属的Constructor对象,最后再准备一个Object[]作为Constructor对象newInstance()方法的实参

// 利用反射构造带参数的类的实例
// 得到类实例
Class clazz = Class.forName(User.class.getName());
Class[] paramType = new Class[] { String.class, int.class, String.class };
// 得到构造方法
Constructor constructor = clazz.getConstructor(paramType);
// 实例构造方法的参数数组
Object[] params = new Object[] { "Paulz", 29, "111111" };
// 利用带参构造方法实例类
Object obj = constructor.newInstance(params);
System.out.println(((User) obj).getUserName());// 结果:Paulz


2. cope一个对象,封装各个属性值

public static Object copy(Object obj) throws Exception {
	// 获得对象的类型
	Class clazz = obj.getClass();
	System.out.println("该对象的类型是 = " + clazz.getName());
	// 通过默认构造方法创建一个新的对象,视其参数动态决定调用哪个构造函数
	Object objectCopy = clazz.getConstructor(new Class[] {}).newInstance(new Object[] {});
	// 获得对象的所有属性,包括私有属性
	Field[] fields = clazz.getDeclaredFields();
	for (int i = 0; i < fields.length; i++) {
		Field field = fields[i];

		// 获得数组中对应的属性名称
		String fieldName = field.getName();

		// 获得相应属性的getter和setter方法名称
		String letter = fieldName.substring(0, 1).toUpperCase();
		String getName = "get" + letter + fieldName.substring(1);
		String setName = "set" + letter + fieldName.substring(1);

		// 获得相应的getter和setter方法
		Method getMethod = clazz.getMethod(getName, new Class[] {});
		Method setMethod = clazz.getMethod(setName, new Class[] { field.getType() });

		// 调用源对象的getter方法
		Object value = getMethod.invoke(obj, new Object[] {});
		System.out.println("value = " + value);

		// 调用copy的setter方法,将源对象值赋给新对象对应的方法
		setMethod.invoke(objectCopy, new Object[] { value });
	}
	return objectCopy;
}


二、实现例子

ReflectUtils代码:

package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;

public class ReflectUtils {
	/**
	 * 利用带参构造方法生成类实例
	 * 
	 * @param map
	 *            参数
	 * @param clazz
	 *            返回类类型
	 * @return
	 * @throws Exception
	 * @throws
	 */
	public static <T> T getObject(Map<String, Object> map, Class<T> clazz) throws Exception {
		if (map == null) {
			return null;
		}
		Constructor<T> constructor = clazz.getConstructor(Map.class);
		T obj = constructor.newInstance(map);
		return obj;
	}

	/**
	 * 拷贝一个新对象
	 * 
	 * @param obj
	 *            对象
	 * @param clazz
	 *            对象类型
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static <T> T copy(T obj) throws Exception {
		// 获得对象的类型
		Class<T> clazz = (Class<T>) obj.getClass();
		// 通过默认构造方法创建一个新的对象
		T objCopy = clazz.newInstance();
		// 获得对象的所有属性,包括私有属性
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			// 获得属性名称
			String fieldName = field.getName();

			// 获得相应的属性的getter和setter方法名称
			String letter = fieldName.substring(0, 1).toUpperCase();
			String getName = "get" + letter + fieldName.substring(1);
			String setName = "set" + letter + fieldName.substring(1);
			Method getMethod = clazz.getMethod(getName, new Class[] {});
			Method setMethod = clazz.getMethod(setName, new Class[] { field.getType() });

			// 调用源对象的getter方法
			Object value = getMethod.invoke(obj, new Object[] {});

			// 调用copy的setter方法,将源对象值赋给新对象对应的方法
			setMethod.invoke(objCopy, new Object[] { value });
		}
		return objCopy;
	}
}


User代码:

package reflect;

import java.util.Map;

public class User {

	private String userName;// 姓名
	private Integer age;// 年龄
	public String password;// 密码

	public User() {
	}

	/**
	 * 带参数的构造函数
	 * 
	 * @param userName
	 *            姓名
	 * @param age
	 *            年龄
	 * @param password
	 *            密码
	 */
	public User(String userName, Integer age, String password) {
		this.userName = userName;
		this.age = age;
		this.password = password;
	}

	/**
	 * 带参数的构造函数
	 * 
	 * @param map
	 *            参数
	 */
	public User(Map<String, Object> map) {
		if (map == null) {
			throw new IllegalArgumentException("user");
		}
		this.userName = String.valueOf(map.get("userName"));
		this.age = Integer.valueOf(String.valueOf(map.get("age")));
		this.password = String.valueOf(map.get("password"));
	}

	@Override
	public String toString() {
		return "[ Name = " + this.userName + " | age = " + this.age + " | Password = " + this.password + " ]";
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

}


ReflectTest代码:

package reflect;

import java.util.HashMap;
import java.util.Map;

public class ReflectTest {
	public static void main(String[] args) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("userName", "殷建卫");
		map.put("age", 28);
		map.put("password", "123456");
		User user = null;
		try {
			// 创建对象
			user = ReflectUtils.getObject(map, User.class);
			System.out.println("user对象:" + user.toString());
			// 拷贝对象
			User userCopy = ReflectUtils.copy(user);
			System.out.println("userCopy对象:" + userCopy.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}

输出:

user对象:[ Name = 殷建卫 | age = 28 | Password = 123456 ]

userCopy对象:[ Name = 殷建卫 | age = 28 | Password = 123456 ]



资源下载链接为: https://pan.quark.cn/s/1bfadf00ae14 “STC单片机电压测量”是一个以STC系列单片机为基础的电压检测应用案例,它涵盖了硬件电路设计、软件编程以及数据处理等核心知识点。STC单片机凭借其低功耗、高性价比和丰富的I/O接口,在电子工程领域得到了广泛应用。 STC是Specialized Technology Corporation的缩写,该公司的单片机基于8051内核,具备内部振荡器、高速运算能力、ISP(在系统编程)和IAP(在应用编程)功能,非常适合用于各种嵌入式控制系统。 在源代码方面,“浅雪”风格的代码通常简洁易懂,非常适合初学者学习。其中,“main.c”文件是程序的入口,包含了电压测量的核心逻辑;“STARTUP.A51”是启动代码,负责初始化单片机的硬件环境;“电压测量_uvopt.bak”和“电压测量_uvproj.bak”可能是Keil编译器的配置文件备份,用于设置编译选项和项目配置。 对于3S锂电池电压测量,3S锂电池由三节锂离子电池串联而成,标称电压为11.1V。测量时需要考虑电池的串联特性,通过分压电路将高电压转换为单片机可接受的范围,并实时监控,防止过充或过放,以确保电池的安全和寿命。 在电压测量电路设计中,“电压测量.lnp”文件可能包含电路布局信息,而“.hex”文件是编译后的机器码,用于烧录到单片机中。电路中通常会使用ADC(模拟数字转换器)将模拟电压信号转换为数字信号供单片机处理。 在软件编程方面,“StringData.h”文件可能包含程序中使用的字符串常量和数据结构定义。处理电压数据时,可能涉及浮点数运算,需要了解STC单片机对浮点数的支持情况,以及如何高效地存储和显示电压值。 用户界面方面,“电压测量.uvgui.kidd”可能是用户界面的配置文件,用于显示测量结果。在嵌入式系统中,用
资源下载链接为: https://pan.quark.cn/s/abbae039bf2a 在 Android 开发中,Fragment 是界面的一个模块化组件,可用于在 Activity 中灵活地添加、删除或替换。将 ListView 集成到 Fragment 中,能够实现数据的动态加载与列表形式展示,对于构建复杂且交互丰富的界面非常有帮助。本文将详细介绍如何在 Fragment 中使用 ListView。 首先,需要在 Fragment 的布局文件中添加 ListView 的 XML 定义。一个基本的 ListView 元素代码如下: 接着,创建适配器来填充 ListView 的数据。通常会使用 BaseAdapter 的子类,如 ArrayAdapter 或自定义适配器。例如,创建一个简单的 MyListAdapter,继承自 ArrayAdapter,并在构造函数中传入数据集: 在 Fragment 的 onCreateView 或 onActivityCreated 方法中,实例化 ListView 和适配器,并将适配器设置到 ListView 上: 为了提升用户体验,可以为 ListView 设置点击事件监听器: 性能优化也是关键。设置 ListView 的 android:cacheColorHint 属性可提升滚动流畅度。在 getView 方法中复用 convertView,可减少视图创建,提升性能。对于复杂需求,如异步加载数据,可使用 LoaderManager 和 CursorLoader,这能更好地管理数据加载,避免内存泄漏,支持数据变更时自动刷新。 总结来说,Fragment 中的 ListView 使用涉及布局设计、适配器创建与定制、数据绑定及事件监听。掌握这些步骤,可构建功能强大的应用。实际开发中,还需优化 ListView 性能,确保应用流畅运
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值