1.爲什麼要學內省?
開發框架時,經常需要使用java對象的屬性來封裝程序的數據,每次都使用反射技術完成此類操作過於麻煩,所以sun公司開發了一套API,專門用於操作java對象的屬性。
2.反射技術
以後我們能開發框架的時候,經常需要把一些數據封裝到對象中去
需求:編寫一個工廠方法根據配置文件的內容,工廠方法返回對應的對象,並且對象要有對應的屬性值
Person.java
package day01.introspector;
public class Person {
int id;
String name;
public Person(int id, String name) {
super();
this.id = id;
this.name = name;
}
public Person() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + "]";
}
}
//obj.txt
day01.introspector.Person
id=110
name=張兵傑
//One.java
package day01.introspector;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class One {
Person p = (Person)getInstance();
System.out.println(p);
}
//根據配置文件生產對應的對象並且要把對象的屬性值封裝到對象中
public static Object getInstance() throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, NoSuchFieldException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
BufferedReader bufferedReader = new BufferedReader(new FileReader("obj.txt"));
String className = bufferedReader.readLine();//讀取配置文件獲取到完整的類名
Class clazz = Class.forName(className);
//通過clazz對象獲取到無參的構造方法
Constructor constructor = clazz.getConstructor(null);
//創建對象
Object o = constructor.newInstance(null);
//讀取屬性值
String line = null;
while((line = bufferedReader.readLine())!=null){
String[] datas = line.split("=");
//通過屬性名獲取到當前的Field對象
Field field = clazz.getDeclaredField(datas[0]);
if(field.getType() == int.class){
field.set(o, Integer.parseInt(datas[1]));
}else{
field.set(o, datas[1]);
}
}
return o;
}
}
內省======一個變態的反射
內省主要解決的問題:把對象的屬性數據封裝到對象中去
//Two.java
package day01.introspector;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Two {
public static void main(String args[]) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException{
testProperty1();
}
public static void testProperty1() throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
Person p = new Person();
//屬性描述器 屬性名+屬性類
PropertyDescriptor descriptor = new PropertyDescriptor("id",Person.class);
//獲取屬性對應的get或者是set方法設置或者獲取屬性
Method m = descriptor.getWriteMethod();//獲取屬性set方法
//執行該方法設置屬性值
m.invoke(p, 110);
//Method類代表一個方法,invoke(調用)就是調用Method類代表的方法
Method readMethod = descriptor.getReadMethod();//獲取屬性get方法
System.out.println(p);
System.out.println(readMethod.invoke(p, null));
}
public void getAllProperty() throws IntrospectionException{
//Introspector 內省類
BeanInfo beanInfo = Introspector.getBeanInfo(Person.class);
//通過BeanInfo獲取所有的屬性描述器
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();//獲取一個類中的所有屬性描述器
for (PropertyDescriptor propertyDescriptor : descriptors) {
System.out.println(propertyDescriptor.getReadMethod());//get方法
}
}
}
BeanUtils:
BeanUtils主要解決的問題:把對象的屬性數據封裝到對象中BeanUtils的好處
1.BeanUtils設置屬性值時候,如果屬性是基本數據類型,BeanUtils會自動幫我們轉化數據類型
2.BeanUtils設置屬性值時候,底層也是依賴於get,set方法設置以及獲取屬性值的
3.BeanUtils設置屬性值,如果設置的屬性是其他的引用 類型數據,比如Date,那麼這時候必須要註冊一個類型轉換器
//Three.java
package day01.introspector;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.text.SimpleDateFormat;
import javax.xml.crypto.Data;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
public class Three {
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException {
//從文件中讀取到的數據都是字符串的數據,或者是表單提交的數據獲取到的時候也是字符串的數據
String id = "110";
String name = "張兵傑";
Person p = new Person();
BeanUtils.setProperty(p, "id", id);
BeanUtils.setProperty(p, "name", name);
System.out.println(p);
//日期不會自動轉換,需要自己註冊一個類型轉換器
String birthday = "2017-7-25";
ConvertUtils.register(new Converter() {
@Override
public Object convert(Class type, Object value) {//type目前所遇到的數據類型。value目前參數的值
Date date = null;
try{
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
date = dateFormat.parse((String)value);
}catch(Exception e){
e.printStackTrace();
}
return date;
}
},Date.class);
}
}