內省(瞭解)
內省的目標是得到JavaBean屬性的讀、寫方法的反射對象,通過反射對JavaBean屬性進行操作的一組API。例如User類有名爲username的JavaBean屬性,通過兩個Method對象(一個是getUsenrmae(),一個是setUsername())來操作User對象。
如果你還不能理解內省是什麼,那麼我們通過一個問題來了解內省的作用。現在我們有一個Map,內容如下:
Map<String,String> map = new HashMap<String,String>(); map.put("username", "admin"); map.put("password", "admin123"); |
public class User { private String username; private String password;
public User(String username, String password) { this.username = username; this.password = password; } public User() { } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String toString() { return "User [username=" + username + ", password=" + password + "]"; } } |
現在需要把map的數據封裝到一個User對象中!User類有兩個JavaBean屬性,一個叫username,另一個叫password。
你可能想到的是反射,通過map的key來查找User類的Field!這麼做是沒有問題的,但我們要知道類的成員變量是私有的,雖然也可以通過反射去訪問類的私有的成員變量,但我們也要清楚反射訪問私有的東西是有“危險”的,所以還是建議通過getUsername和setUsername來訪問JavaBean屬性。
2.1 內省之獲取BeanInfo
我們這裏不想去對JavaBean規範做過多的介紹,所以也就不在多介紹BeanInfo的“出身”了。你只需要知道如何得到它,以及BeanInfo有什麼。
通過java.beans.Introspector的getBeanInfo()方法來獲取java.beans.BeanInfo實例。
BeanInfo beanInfo = Introspector.getBeanInfo(User.class); |
2.2 得到所有屬性描述符(PropertyDescriptor)
通過BeanInfo可以得到這個類的所有JavaBean屬性的PropertyDescriptor對象。然後就可以通過PropertyDescriptor對象得到這個屬性的getter/setter方法的Method對象了。
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors(); |
每個PropertyDescriptor對象對應一個JavaBean屬性:
- String getName():獲取JavaBean屬性名稱;
- Method getReadMethod:獲取屬性的讀方法;
- Method getWriteMethod:獲取屬性的寫方法。
2.3 完成Map數據封裝到User對象中
public void fun1() throws Exception { Map<String,String> map = new HashMap<String,String>(); map.put("username", "admin"); map.put("password", "admin123");
BeanInfo beanInfo = Introspector.getBeanInfo(User.class);[崔1]
PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();[崔2]
User user = new User();[崔3] for(PropertyDescriptor pd : pds)[崔4] { String name = pd.getName();[崔5] String value = map.get(name);[崔6] Method writeMethod = pd.getWriteMethod();[崔8] writeMethod.invoke(user, value);[崔9] } }
System.out.println(user); } |
3 commons-beanutils
提到內省,不能不提commons-beanutils這個工具。它底層使用了內省,對內省進行了大量的簡化!
使用beanutils需要的jar包:
- commons-beanutils.jar;
- commons-logging.jar;
3.1 設置JavaBean屬性
User user = new User();
BeanUtils.setProperty(user, "username", "admin");[崔10] BeanUtils.setProperty(user, "password", "admin123");[崔11]
System.out.println(user); |
3.2 獲取JavaBean屬性
User user = new User("admin", "admin123");
String username = BeanUtils.getProperty(user, "username");[崔12] String password = BeanUtils.getProperty(user, "password");[崔13]
System.out.println("username=" + username + ", password=" + password); |
3.3 封裝Map數據到JavaBean對象中
Map<String,String> map = new HashMap<String,String>(); map.put("username", "admin"); map.put("password", "admin123");
User user = new User();
BeanUtils.populate(user, map);[崔14]
System.out.println(user); |
工具類:將Map直接封裝到Bean
public static <T> T toBean(Map map, Class<T> clazz) {
try {
/*
* 1. 創建指定類型的javabean對象
*/
T bean = clazz.newInstance();
/*
* 2. 把數據封裝到javabean中
*/
BeanUtils.populate(bean, map);
/*
* 返回javabean對象
*/
return bean;
} catch(Exception e) {
throw new RuntimeException(e);
}
}
測試:
public class Demo1 {
@Test
public void fun1() throws Exception {
String className = "cn.itcast.domain.Person";
Class clazz = Class.forName(className);
Object bean = clazz.newInstance();
BeanUtils.setProperty(bean, "name", "張三");
BeanUtils.setProperty(bean, "age", "23");
BeanUtils.setProperty(bean, "gender", "男");
BeanUtils.setProperty(bean, "xxx", "XXX");
String age = BeanUtils.getProperty(bean, "age");
System.out.println(age);
System.out.println(bean);
}
/*
* 把map中的屬性直接封裝到一個bean中
*
* Map: {"username":"zhangSan", "password","123"}
* 我們要把map的數據封裝到一個javabean中!要求map的key與bean的屬性名相同!
*/
@Test
public void fun2() throws Exception {
Map<String,String> map = new HashMap<String,String>();
map.put("username", "zhangSan");
map.put("password", "123");
User user = new User();
BeanUtils.populate(user, map);
System.out.println(user);
}
@Test
public void fun3() {
Map<String,String> map = new HashMap<String,String>();
map.put("username", "zhangSan");
map.put("password", "123");
/*
* request.getParameterMap();
*/
User user = CommonUtils.toBean(map, User.class);
System.out.println(user);
}
commons-beanutils
是Apache開源組織提供的用於操作JAVA BEAN的工具包。使用commons-beanutils
,我們可以很方便的對bean對象的屬性進行操作。今天爲大家介紹一下該包的常用方法。
在介紹常用類之前,我們先來 編寫一個用於測試的BEAN類:
package com.gujin.entity;
public class UserInfo
{
private String userId;
private String userName;
public UserInfo()
{
}
public UserInfo(String userId, String userName)
{
this.userId = userId;
this.userName = userName;
}
public String getUserId()
{
return userId;
}
public void setUserId(String userId)
{
this.userId = userId;
}
public String getUserName()
{
return userName;
}
public void setUserName(String userName)
{
this.userName = userName;
}
@Override
public String toString()
{
return String.format("{userId:%s,userName:%s}", userId, userName);
}
}
MethodUtils
MethodUtils
通過反射訪問對象的方法並且執行方法。
方法摘要:
返回值 | 方法名 | 說明 |
---|---|---|
static int | clearCache() | 清空方法緩存 |
static Method | getAccessibleMethod(Class<?> clazz, Method method) | 返回一個可訪問的方法 |
static Method | getAccessibleMethod(Class<?> clazz, String methodName, Class<?> parameterType) | 返回一個可訪問的方法 |
static Method | getAccessibleMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) | 返回一個可訪問的方法 |
static Method | getAccessibleMethod(Method method) | 返回一個可訪問的方法 |
static Method | getMatchingAccessibleMethod(Class<?> clazz, String methodName, Class<?>[] parameterTypes) | 查找與方法名及參數匹配的可訪問方法 |
static Class<?> | getPrimitiveType(Class<?> wrapperType) | 獲得包裝類的基本數據類型 |
static Class<?> | getPrimitiveWrapper(Class<?> primitiveType) | 獲得基本數據類型的包裝類型 |
static Object | invokeExactMethod(Object object, String methodName, Object arg) | 執行方法 |
static Object | invokeExactMethod(Object object, String methodName, Object[] args) | 執行方法 |
static Object | invokeExactMethod(Object object, String methodName, Object[] args, Class<?>[] parameterTypes) | 執行方法 |
static Object | invokeExactStaticMethod(Class<?> objectClass, String methodName, Object arg) | 執行靜態方法 |
static Object | invokeExactStaticMethod(Class<?> objectClass, String methodName, Object[] args) | 執行靜態方法 |
static Object | invokeExactStaticMethod(Class<?> objectClass, String methodName, Object[] args, Class<?>[] parameterTypes) | 執行靜態方法 |
static Object | invokeMethod(Object object, String methodName, Object arg) | 執行方法 |
static Object | invokeMethod(Object object, String methodName, Object[] args) | 執行方法 |
static Object | invokeMethod(Object object, String methodName, Object[] args, Class<?>[] parameterTypes) | 執行方法 |
static Object | invokeStaticMethod(Class<?> objectClass, String methodName, Object arg) | 執行靜態方法 |
static Object | invokeStaticMethod(Class<?> objectClass, String methodName, Object[] args) | 執行靜態方法 |
static Object | invokeStaticMethod(Class<?> objectClass, String methodName, Object[] args, Class<?>[] parameterTypes) | 執行靜態方法 |
static boolean | isAssignmentCompatible(Class<?> parameterType, Class<?> parameterization) | 確定是否可以使用一個類型作爲方法調用參數 |
static void | setCacheMethods(boolean cacheMethods) | 設置緩存方法 |
static Class<?> | toNonPrimitiveClass(Class<?> clazz) | 如果是簡單數據類型則返回對應的包裝類,否則返回本身 |
使用示例:
package com.gujin.beanutils;
import java.lang.reflect.Method;
import org.apache.commons.beanutils.MethodUtils;
import org.junit.Test;
import com.gujin.entity.UserInfo;
public class MethodUtilsTest
{
@Test
public void test() throws Exception
{
UserInfo userInfo = new UserInfo();
// 通過方法名和參數類型獲得可訪問方法
Method method = MethodUtils.getAccessibleMethod(UserInfo.class,
"setUserId", String.class);
method.invoke(userInfo, "jianggujin");
// 可以直接通過invokeMethod執行方法
MethodUtils.invokeMethod(userInfo, "setUserName", "蔣固金");
System.out.println(userInfo);
}
}
運行結果:
{userId:jianggujin,userName:蔣固金}
ConstructorUtils
ConstructorUtils
通過反射提供了構造方法相關的便捷操作方法。
方法摘要:
返回值 | 方法名 | 說明 |
---|---|---|
static <T> Constructor<T> | getAccessibleConstructor(Class<T> klass, Class<?> parameterType) | 獲得含有一個形參的構造方法 |
static <T> Constructor<T> | getAccessibleConstructor(Class<T> klass, Class<?>[] parameterTypes) | 獲得含有指定類型形參的構造方法 |
static <T> Constructor<T> | getAccessibleConstructor(Constructor<T> ctor) | 獲得可訪問構造方法 |
static <T> T | invokeConstructor(Class<T> klass, Object arg) | 執行構造方法 |
static <T> T | invokeConstructor(Class<T> klass, Object[] args) | 執行構造方法 |
static <T> T | invokeConstructor(Class<T> klass, Object[] args, Class<?>[] parameterTypes) | 執行構造方法 |
static <T> T | invokeExactConstructor(Class<T> klass, Object arg) | 執行構造方法 |
static <T> T | invokeExactConstructor(Class<T> klass, Object[] args) | 執行構造方法 |
static <T> T | invokeExactConstructor(Class<T> klass, Object[] args, Class<?>[] parameterTypes) | 執行構造方法 |
使用示例:
package com.gujin.beanutils;
import java.lang.reflect.Constructor;
import org.apache.commons.beanutils.ConstructorUtils;
import org.junit.Test;
import com.gujin.entity.UserInfo;
public class ConstructorUtilsTest
{
@Test
public void test() throws Exception
{
Constructor<UserInfo> constructor = ConstructorUtils
.getAccessibleConstructor(UserInfo.class, new Class[] {
String.class, String.class });
System.out.println(constructor.newInstance("jianggujin", "蔣固金"));
// 更簡潔的寫法
UserInfo userInfo = ConstructorUtils.invokeConstructor(UserInfo.class,
new String[] { "jianggujin", "蔣固金" });
System.out.println(userInfo);
}
}
運行結果:
{userId:jianggujin,userName:蔣固金}
{userId:jianggujin,userName:蔣固金}
PropertyUtils
PropertyUtils
通過反射提供了對象屬性的便捷操作方法。
方法摘要:
返回值 | 方法名 | 說明 |
---|---|---|
static void | addBeanIntrospector(BeanIntrospector introspector) | 添加一個BeanIntrospector |
static void | clearDescriptors() | 清空所有屬性描述信息 |
static void | copyProperties(Object dest, Object orig) | 複製屬性 |
static Map<String,Object> | describe(Object bean) | 屬性描述 |
static Object | getIndexedProperty(Object bean, String name) | 指定索引屬性值 |
static Object | getIndexedProperty(Object bean, String name, int index) | 指定索引屬性值 |
static Object | getMappedProperty(Object bean, String name) | 獲得Map屬性 |
static Object | getMappedProperty(Object bean, String name, String key) | 獲得Map屬性中指定鍵對應的值 |
static Object | getNestedProperty(Object bean, String name) | 獲得嵌套屬性 |
static Object | getProperty(Object bean, String name) | 獲得屬性 |
static PropertyDescriptor | getPropertyDescriptor(Object bean, String name) | 獲得屬性描述 |
static PropertyDescriptor[] | getPropertyDescriptors(Class<?> beanClass) | 獲得屬性描述 |
static PropertyDescriptor[] | getPropertyDescriptors(Object bean) | 獲得屬性描述 |
static Class<?> | getPropertyType(Object bean, String name) | 獲得屬性類型 |
static Method | getReadMethod(PropertyDescriptor descriptor) | 返回一個可訪問的屬性的getter方法 |
static Object | getSimpleProperty(Object bean, String name) | 返回屬性值 |
static Method | getWriteMethod(PropertyDescriptor descriptor) | 返回一個可訪問的屬性的setter方法 |
static boolean | isReadable(Object bean, String name) | 判斷是否爲可讀屬性 |
static boolean | isWriteable(Object bean, String name) | 判斷是否爲可寫屬性 |
static boolean | removeBeanIntrospector(BeanIntrospector introspector) | 移除BeanIntrospector |
static void | resetBeanIntrospectors() | 重置BeanIntrospector |
static void | setIndexedProperty(Object bean, String name, int index, Object value) | 設置指定索引屬性值 |
static void | setIndexedProperty(Object bean, String name, Object value) | 設置指定索引屬性值 |
static void | setMappedProperty(Object bean, String name, Object value) | 設置Map屬性的值 |
static void | setMappedProperty(Object bean, String name, String key, Object value) | 設置Map屬性指定鍵的值 |
static void | setNestedProperty(Object bean, String name, Object value) | 設置嵌套屬性的值 |
static void | setProperty(Object bean, String name, Object value) | 設置屬性值 |
static void | setSimpleProperty(Object bean, String name, Object value) | 設置屬性值 |
使用示例:
package com.gujin.beanutils;
import org.apache.commons.beanutils.PropertyUtils;
import org.junit.Test;
import com.gujin.entity.UserInfo;
public class PropertyUtilsTest
{
@Test
public void test() throws Exception
{
UserInfo userInfo = new UserInfo("jianggujin", "蔣固金");
UserInfo copyed = new UserInfo();
PropertyUtils.copyProperties(copyed, userInfo);
System.out.println(copyed);
System.out.println(PropertyUtils.describe(userInfo));
PropertyUtils.setProperty(userInfo, "userId", "gjjiang");
System.out.println(userInfo);
}
}
運行結果:
{userId:jianggujin,userName:蔣固金}
{userId=jianggujin, class=class com.gujin.entity.UserInfo, userName=蔣固金}
{userId:gjjiang,userName:蔣固金}
BeanUtils
BeanUtils
通過反射提供了Bean對象的便捷操作方法。
方法摘要:
返回值 | 方法名 | 說明 |
---|---|---|
static Object | cloneBean(Object bean) | 克隆對象 |
static void | copyProperties(Object dest, Object orig) | 複製屬性 |
static void | copyProperty(Object bean, String name, Object value) | 複製屬性 |
static <K,V> Map<K,V> | createCache() | 創建緩存 |
static Map<String,String> | describe(Object bean) | 描述 |
static String[] | getArrayProperty(Object bean, String name) | 返回指定屬性的值,作爲字符串數組返回 |
static String | getIndexedProperty(Object bean, String name) | 獲取指定索引位置對象作爲字符串返回 |
static String | getIndexedProperty(Object bean, String name, int index) | 獲取指定索引位置對象作爲字符串返回 |
static String | getMappedProperty(Object bean, String name) | 獲得Map屬性值作爲字符串返回 |
static String | getMappedProperty(Object bean, String name, String key) | 獲得Map屬性中指定鍵的值作爲字符串返回 |
static String | getNestedProperty(Object bean, String name) | 獲得嵌套屬性作爲字符串返回 |
static String | getProperty(Object bean, String name) | 獲得屬性值作爲字符串返回 |
static String | getSimpleProperty(Object bean, String name) | 獲得屬性值作爲字符串返回 |
static void | populate(Object bean, Map<String,? extends Object> properties) | 將Map中的數據注入到Bean對象中 |
static void | setProperty(Object bean, String name, Object value) | 設置屬性值 |
使用示例:
package com.gujin.beanutils;
import java.util.HashMap;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import com.gujin.entity.UserInfo;
public class BeanUtilsTest
{
@Test
public void test() throws Exception
{
UserInfo userInfo = new UserInfo();
HashMap<String, String> properties = new HashMap<String, String>();
properties.put("userId", "jianggujin");
properties.put("userName", "蔣固金");
BeanUtils.populate(userInfo, properties);
System.out.println(userInfo);
}
}
運行結果:
{userId:jianggujin,userName:蔣固金}
ConvertUtils
ConvertUtils
提供了數據類型相互轉換的方法。
方法摘要:
方法摘要:
返回值 | 方法名 | 說明 |
---|---|---|
static String | convert(Object value) | 將對象轉換爲字符串 |
static Object | convert(Object value, Class<?> targetType) | 將對象轉換爲指定數據類型對象 |
static Object | convert(String[] values, Class<?> clazz) | 將數組轉換爲指定數據類型對象 |
static Object | convert(String value, Class<?> clazz) | 將字符串轉換爲指定數據類型對象 |
static void | deregister() | 移除所有已經註冊的轉換器 |
static void | deregister(Class<?> clazz) | 移除指定類型的轉換器 |
static Converter | lookup(Class<?> clazz) | 查找指定類型的轉換器 |
static Converter | lookup(Class<?> sourceType, Class<?> targetType) | 查找將指定類型轉換爲另一種類型的轉換器 |
static void | register(Converter converter, Class<?> clazz) | 註冊轉換器 |
使用示例:
package com.gujin.beanutils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.junit.Test;
public class ConvertUtilsTest
{
@Test
public void test() throws Exception
{
ConvertUtils.register(new Converter()
{
@Override
public <T> T convert(Class<T> arg0, Object arg1)
{
try
{
return (T) new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
.parse((String) arg1);
}
catch (ParseException e)
{
return null;
}
}
}, Date.class);
System.out.println(ConvertUtils
.convert("2016-04-09 12:41:00", Date.class));
}
}
運行結果:
Sat Apr 09 12:41:00 CST 2016