java反射內省機制,Introspector

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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章