(笔记十一)反射、JavaBean、内省、BeanUtils框架

这篇博客深入探讨了Java的反射机制,如何加载并解析类的成员变量、方法和构造函数。同时,文章提到了框架中反射的应用,如通过配置文件动态加载类。此外,还对比了在Java 1.4和1.5中method.invoke()方法的行为差异。通过Person.java和Demo1.java的实际代码示例,进一步解释了这些概念。
摘要由CSDN通过智能技术生成
本节知识常常体验在框架中

1.反射

加载类,并解剖出类的各个组成部分(成员变量、方法、构造方法等)。框架中经常用到,如框架中通过设置配置文件,通过反射来加载对应的类。

a)加载类
Java中的Class类用于代表一个类的字节码,它提供加载类字节码的方法:Class.forName()
其他方法:
类名.class
对象.getClass() 

b)解剖类
getConstructor,getMethod,getFiled //public成员
getDeclaredConstructor... //所有成员
注:私有成员通过setAccessible(true)设置它为public

c)例子

package reflect;

import java.util.List;

public class Person {
	public String name = "aaa";

	public Person() {
		System.out.println("person");
	}	
	public Person(String name) {
		System.out.println("person name");
	}
	private Person(List list){
		System.out.println("list");
	}
	
	public void Msg(){
		System.out.println("hello");
	}
	public void Msg(String msg){
		System.out.println(msg);
	}
	
	public void Msg(String[] msg){
		System.out.println(msg);
	}
}
package reflect;

import java.util.List;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;

import org.junit.Test;

public class Demo {

	// 反射构造函数:public Person()
	@Test
	public void Test1() throws Exception {
		Class clazz = Class.forName("reflect.Person");
		Constructor c = clazz.getConstructor(null);
		Person p = (Person) c.newInstance(null);
	}

	// 反射构造函数:public Person(String name)
	@Test
	public void Test2() throws Exception {
		Class clazz = Class.forName("reflect.Person");
		Constructor c = clazz.getConstructor(String.class);
		Person p = (Person) c.newInstance("aaa");
	}

	// 反射构造函数:private Person(List list)
	@Test
	public void Test3() throws Exception {
		Class clazz = Class.forName("reflect.Person");
		Constructor c = clazz.getDeclaredConstructor(List.class);	//获取私有
		c.setAccessible(true);	//设置为可访问
		Person p = (Person) c.newInstance(new ArrayList());
	}
	
	另一种方式,只能创建无参构造函数的对象
	@Test
	public void Test4() throws Exception {
		Class clazz = Class.forName("reflect.Person");
		Person p=(Person)clazz.newInstance();	
	}
	
	//反射调用方法
	@Test
	public void Test5() throws Exception{
		Person p=new Person();
		Class clazz = Class.forName("reflect.Person");
		//无参Msg方法
		Method method=clazz.getMethod("Msg", null);
		method.invoke(p, null);		
		//数组参数的Msg方法,1.5兼容1.4
		method=clazz.getMethod("Msg", String[].class);
		method.invoke(p, new Object[]{new String[]{"haha"}});		
	}
}

d)method.invoke在1.4与1.5中的差异

1.4中,method.invoke(Object o,Object obj[]),第一个参数为对象,第二个为参数列表,如
会将参数列表的数组,进行拆分,然后传递给方法的对应参数

1.5出现可变参数,method.nvoke(Object obj, Object... args),为了兼容1.4,继续拆分。
//反射数组参数的Msg方法
method=clazz.getMethod("Msg", String[].class);
method.invoke(p, new String[]{"aa","bb"}); //异常
原因:虽然1.5是可变参数,表面上直接去调用Msg(String[] arr),但兼容1.4,继续拆分
String[]可看作Object[],拆分后会查找Msg(String s1,String s2)的方法,该方法不存在,异常
解决:
method.invoke(p,(Object)new String[]{"aaa","bbb"}); //方法1,Object仅仅是一个对象,拆成一个String[]
method.invoke(p,new Object[]{new String[]{"aaa","bbb"}}); //方法2

e)字段
假设Person类,包含字段String name
Person p=new Person();
Field f=clazz.getField("name");
String name=(String)f.get(p); //1.直接获取某个对象的字段值
Class type=f.getType(); //2.安全获取字段值
Object value=f.get(p);
if(type.equals(String.class))
{
String n=(String)f.get(p);
}

2.JavaBean
本身是一种java类(封装数据),它的属性根据get或set来决定,格式:
a)必须有无参构造函数
b)字段必须私有
c)提供标准的getter或setter
public class Animal {
	private String name;
	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}
d)其实get或set开头的方法,称为类的属性

3.内省(Introspector)
利用反射,可以对JavaBean处理(换句话说,反射来处理类),但是过于麻烦,sun公司开发一套API,专门用于操作对象的属性。
内省提供了对JavaBean类属性、事件的一种缺省处理方法。通过getter、setter访问器,这是默认规则,通过内省API不需要了解规则来访问访问器
public class Person {
	private String Id;
	private String FirstName;
	public void setId(String id) {
		this.Id = id;
	}
	public String getId() {
		return this.Id;
	}
	public void setFirstName(String firstName) {
		this.FirstName = firstName;
	}
	public String getFirstName() {
		return this.FirstName;
	}
}
public void Test() throws Exception{		
	//获取Bean信息
	BeanInfo info=Introspector.getBeanInfo(Person.class);
	//获取Bean所有属性
	PropertyDescriptor[] pds=info.getPropertyDescriptors();
	for(PropertyDescriptor p : pds){
		System.out.println(p.getName());			
	}
	//操作id属性
	Person person=new Person();
	PropertyDescriptor pd=new PropertyDescriptor("Id",Person.class);
	Method method=pd.getWriteMethod();
	method.invoke(person, "N001");
	System.out.println(person.getId());
	//得到属性类型
	System.out.println(pd.getPropertyType());
}

4.BeanUtils框架,类似与内省,但提供更加方便的操作JavaBean
step1:在项目中新建lib文件夹,存放主要存放jar包,添加commons-logging.jar和commons-beanutils.jar.
step2:选中jar包,右键add Build Path,添加引用

Person.java文件

import java.util.Date;

public class Person {
	private String name;
	private int age;
	private Date birthday;
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}	
}

Demo1.java文件

import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.junit.Test;

public class Demo1 {
	//基本用法
	@Test
	public void Test1() throws IllegalAccessException, InvocationTargetException{
		Person p=new Person();	
		BeanUtils.setProperty(p, "name", "zhangsan");
		System.out.println(p.getName());
	}
	//注册日期转换器
	@Test
	public void Test2() throws IllegalAccessException, InvocationTargetException
	{
		String name="zhangsan";
		String age="20";	
		String birthday="1989-01-01";
		
		//对beanUtils注册一个日期转换器
		ConvertUtils.register(new Converter(){		
			public Object convert(Class type, Object value) {
				if(value==null)
				{
					return null;
				}
				if(!(value instanceof String))
				{
					throw new ConversionException("只支持String类型转换");
				}
				String str=(String)value;
				if(str.trim().equals(""))
				{
					return null;
				}
				SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");
				try
				{
					return df.parse(str);
				}
				catch(ParseException e){
					throw new RuntimeException(e);
				}
			}			
		}, Date.class);		
		Person p=new Person();
		BeanUtils.setProperty(p, "name", name);
		BeanUtils.setProperty(p, "age", age);	//只支持8种基本数据转换
		BeanUtils.setProperty(p, "birthday", birthday);//使用日期转换器
		System.out.println(p.getName());
		System.out.println(p.getAge());
		System.out.println(p.getBirthday().toString());
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值