一、ant下载地址:http://ant.apache.org/bindownload.cgi
二、log4j下载地址:http://logging.apache.org/log4j/2.x/download.html
三、内省
1.什么是内省。
本质上是反射,具体技术由sun替公司提供,集成到了jdk中,可以根据字段名称(String)和字节码对象得到该字段的一个描述:PropertyDescriptor,并由此得到该字段的get、set方法(Method)。
将要使用的JavaBean
1 package com.kdyzm.domain; 2 3 import java.util.Date; 4 5 public class Person { 6 private String name; 7 private Integer age; 8 private Date date; 9 10 public Person(String name, Integer age, Date date) { 11 this.name = name; 12 this.age = age; 13 this.date = date; 14 } 15 public String getName() { 16 return name; 17 } 18 public void setName(String name) { 19 this.name = name; 20 } 21 public Integer getAge() { 22 return age; 23 } 24 public void setAge(Integer age) { 25 this.age = age; 26 } 27 public Date getDate() { 28 return date; 29 } 30 public void setDate(Date date) { 31 this.date = date; 32 } 33 public Person() { 34 } 35 @Override 36 public String toString() { 37 return "Person [name=" + name + ", age=" + age + ", date=" + date + "]"; 38 } 39 }
2.核心类:
(1)PropertyDescriptor类。
[1]继承关系
java.lang.Object
|--java.beans.FeatureDescriptor
|--java.beans.PropertyDescriptor
[2]构造方法
构造方法摘要 |
|
PropertyDescriptor (String propertyName, Class<?> beanClass) 通过调用 getFoo 和 setFoo 存取方法,为符合标准 Java 约定的属性构造一个 PropertyDescriptor。 |
|
PropertyDescriptor (String propertyName, Class<?> beanClass, 此构造方法带有一个简单属性的名称和用于读写属性的方法名称。 |
|
PropertyDescriptor (String propertyName, Method readMethod, 此构造方法带有某一简单属性的名称,以及用来读取和写入属性的 Method 对象。 |
[3]核心方法
Class<?>
|
getPropertyType () 获得属性的 Class 对象。 |
Method
|
getReadMethod () 获得应该用于读取属性值的方法。 |
Method
|
getWriteMethod () 获得应该用于写入属性值的方法。 |
void
|
setReadMethod(Method readMethod) 设置应该用于读取属性值的方法。 |
void
|
setWriteMethod(Method writeMethod) 设置应该用于写入属性值的方法。 |
[4]使用示例。
获的setName方法并给Person对象赋值。
public void test1() throws Exception { Person p=new Person(); /* //这里是通过普通的反射方法来实现的。 Method method=p.getClass().getMethod("setName", String.class); method.invoke(p, "张三"); System.out.println(p); */ //下面通过使用内省的方式来实现该目的。 PropertyDescriptor pd=new PropertyDescriptor("name", p.getClass(),"getName","setName"); Method getName=pd.getReadMethod(); String name=(String) getName.invoke(p); System.out.println(name); Method setName=pd.getWriteMethod(); setName.invoke(p, "小强"); getName=pd.getReadMethod(); System.out.println(getName.invoke(p)); /* * 输出结果: * null * 小强 */ }
不能进行类型的自动转换。
public void test2() throws Exception { Person p=new Person(); PropertyDescriptor pd=new PropertyDescriptor("age", p.getClass()); Method setAge=pd.getWriteMethod(); setAge.invoke(p, "12");//这里只能传递整数类型的参数,所以一定会报错! System.out.println(p); }
(2)BeanInfo接口:专门分析一个JavaBean有多少属性,有哪些属性
[1]获取该接口实例的方法
使用Introspector(内省)类( java.lang.Object )的静态方法:getBeanInfo(Class<?> beanClass)
|--java.bean.Introspector
static BeanInfo |
getBeanInfo(Class<?> beanClass) 在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件。 |
[2]核心方法:getPropertygetDescriptors方法。
PropertyDescriptor[] |
getPropertyDescriptors() 获得 beans PropertyDescriptor。 |
[3]使用方法。
/* * 测试非常不好的类:BeanInfo类,该类并不会将一个Bean对象的所有属性都能解析成功,反而是只要是 * get或者set方法都会 * 解析出来。 * 所以即使是getClass方法该类也会将其作为class属性解析出来。 * 如果不成对,也会解析出来。 */ @Test public void test3() throws Exception { BeanInfo beaninfo=Introspector.getBeanInfo(Person.class); PropertyDescriptor pd[]=beaninfo.getPropertyDescriptors(); for(int i=0;i<pd.length;i++) { String name=pd[i].getName(); System.out.println(name); } }
3.解决类型不匹配的方法:遍历判断
(1)场景:Person类有age成员变量,为int类型,如果想要传递一个字符串给它,一般情况下会报错:不匹配的参数类型。怎样解决这个问题呢?对set方法能接受的参数类型进行判断,如果是整型参数才传递。
(2)手动遍历解决。
/* * 怎样实现将字符串传递到setAge方法中 * 通过使用便利的方式依次对set方法进行遍历 * 这里的JavaBean必须是Integer类型的,否则不识别。 * 这么麻烦的工作apache已经将其简化开发出了第三方jar包:BeanUtils.jar */ @Test public void test4() throws Exception, IllegalArgumentException, IllegalAccessException, InvocationTargetException { String name="小强"; String age="30"; Person p=new Person(); Method methods[]=p.getClass().getDeclaredMethods(); for(Method method:methods) { String methodname=method.getName(); //如果是set方法才行进下一步,get方法直接跳过 if(methodname.startsWith("set")) { Class<?> clazz[]=method.getParameterTypes(); System.out.println(clazz[0]); if(clazz[0].equals(String.class)) { method.invoke(p,name); } else if(clazz[0].equals(Integer.class)) { method.invoke(p, Integer.parseInt(age)); } } else continue; } System.out.println(p); }
4.使用第三方jar包:BeanUtils.jar解决 3 中的问题以及使用第三方jar包的好处。
BeanUtils.jar下载地址:http://commons.apache.org/proper/commons-beanutils/download_beanutils.cgi
(1)BeanUtils.jar是干什么用的?
是一个处理JavaBean的工具包,内部也是使用内省,但是对内省进行了加强。
(2)使用该工具包的好处是什么?
JavaBean中的get方法和set方法不用再成对出现。
能够自动进行基本数据类型的转换(不是基本数据类型不能自动进行转换)。
(3)演示使用BeanUtils设置值。
//演示使用BeanUtils设置值 @Test public void setValueTest() throws Exception, Exception { Person p=new Person(); BeanUtils.setProperty(p,"name", "小强"); BeanUtils.setProperty(p, "age", "45"); BeanUtils.setProperty(p, "date", new Date()); System.out.println(p); }
(4)演示使用BeanUtils获取值。
//演示使用BeanUtils获取值。 @Test public void getValueTest() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { Person p=new Person("小强",24,new Date()); System.out.println(BeanUtils.getProperty(p, "name")); System.out.println(BeanUtils.getProperty(p, "age")); System.out.println(BeanUtils.getProperty(p, "date")); }
(5)使用BeanUtils一次性将获取到的值封装到javaBean中。
//使用Benutils一次性填入所有值的方法 @Test public void setValueAll() throws Exception, InvocationTargetException { Person p=new Person(); Map<String,Object>map=new HashMap<String,Object>(); map.put("name", "小强"); map.put("age", "24"); map.put("date", new Date()); BeanUtils.populate(p, map); //这句是关键 System.out.println(p); //这种方式在分析表单提交的数据并封装成JavaBean的时候使用的非常广泛,因为可以大大节省代码量,注意要使用request对象的getParameterMap()方法。 }