目录 :
1 ) . 框架的概念及用反射技术开发框架的原理
2 ) . 用类加载器的方式管理资源和配置文件
3 ) . 由内省引出JavaBean的讲解
4 ) . 对JavaBean的简单内省操作
5 ) . 对javaBean的复杂内省操作
6 ) . 使用BeanUtils工具包操作JavaBean
一
. 框架的概念及用反射技术开发框架的原理
1 ) . 实现框架的核心原理 :
1.1 往常 : 需要什么 ,造什么 , 拿什么
1.2 反射: 提前做好, 需要什么 , 拿什么
2 ) . 调用方法的两种思路 :
1. 第一种是 我用它 ,因此 我调用他
2. 第二种是 我用它,因此他调用我
3 ) . 框架与工具的区别 :
3.1 框架如同房子,工具如同锁 ,房子是通用型的,锁是功能型的
3.2 框架使用是是 他调用别人, 而 工具 使用是 是 别人 调用他
4 ) . Demo:
package cn.ittext.day01;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.util.Collection;import java.util.Iterator;import java.util.LinkedList;import java.util.Properties;public class ReflectApplication07{//实现一个框架原理public static void main(String[] args ) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException{/** 原始实现:** 需求 : 向一个集合放一些元素并迭代输出** 第一步:创建集合** 第二步:放入元素** 第三步:迭代输出**/Collection<String> collections = new LinkedList<String>();collections .add( "A" );collections .add( "B" );collections .add( "C" );collections .add( "D" );for (Iterator<String> it = collections .iterator() ; it .hasNext();){sop ( it .next());}/** 反射框架实现:*** 第一步 :创建一个资源文件,里边写入相关配置 ; className=java.util.LinkedList** 第二步 :引入资源文件,并将资源文件放入资源类中,因为资源类是键值对的好取值** 第三步 : 关闭系统资源 ; 关乎java程序的资源可不管,因为有GC,但关乎调用系统资源的必须得关,否则会泄露** 第四步 : 获取资源中的值,也就是对象地址** 第五步 : 通过class反射进行实例化** 第六步 : 添加数据** 第七步 : 迭代数据*//*** 资源文件须知 :** 【1】 地址是可找到的,通过鼠标放到相关对象上就可看到地址** 【2】 地址是不可用“” 标识的,否则找不到** 【3】 键与值之间必须是一个=号关联的** 【4】结束标记一定不可以写;否则会出现找不到该类** 【5】配置文件放的地址应该是与src目录在同一级*/InputStream fis = new FileInputStream( "config.properties" );Properties ps = new Properties();ps .load( fis );fis .close();String className = ps .getProperty( "className" );sop ( className );Collection<String> collection = (Collection) Class. forName ( className ).newInstance() ;collection .add( "A" );collection .add( "B" );collection .add( "C" );collection .add( "D" );for (Iterator<String> it = collection .iterator() ; it .hasNext();){sop ( it .next());}}public static void sop(Object obj ){System. out .println( obj );}}5 ). config.properties
className= java.util.LinkedList
小结 :
1.关闭资源关闭的是与本地操作系统相关联数据的资源,关闭的是物理资源; 而逻辑资源,也就是java源程序产生的垃圾则由GC进行处理
二. 用类加载器的方式管理资源和配置文件
1 ) . 资源配置文件路径的设置 :
1.1 须知 : 必须是 绝对路径的,而绝对路径又是不固定的(硬编码),因此通过getRealPath() 获取在硬盘上的总目录 + 在 项目中存放的 路径
1.2 为何不用相对路径? 因为相对路径是相对的每一个指令运行的当前目录, 这个是不固定的
2 ) . 获取类加载器加载资源文件的方式:"
2.1 类.class 获取类字节码文件 --> . getClassloader() 获取类加载器 --> .getResourceAstream("classPath下的路径") 获取资源文件地址
3 ) . Demo:
package cn.ittext.day01;import java.io.FileInputStream ;import java.io.IOException;import java.io.InputStream;import java.util.Properties;public class ReflectApplication08{public static void main(String[] args ) throws IOException{/*** 庖丁解牛 : 类加载器的加载路径详解** 常用 : 第三种与第四种方式; 相对的是本项目中的class类字节码文件地址, 绝对的是bin下的精确地址** 总结:** [1]class类加载器直接加载配置文件的方法getResourceAsStream() 底层调用的还是getClassLoader() 类加载器** [2] 当配置文件放在不同目录时, 需要使用绝对路径去加载配置文件地址****//*** 第一种方式 : 配置文件与 src 路径平级时的加载方式** 分析 : 这种方式 是 相对的 ,几乎不用,因为 正常情况下 地址是不固定的**//*InputStream is =new FileInputStream("config.properties");Properties ps =new Properties();ps.load(is);String className = ps.getProperty("className");sop (className);*//*** 第二种方式 : 配置文件在 src 目录下,用类加载的方式加载资源文件 --> 完整版** 分析 : 这种方式配置的路径是绝对路径**//* //通过类获取字节码文件,再获取类加载器,再获取加载资源文件方法以此加载资源配置文件InputStream resourceAsStream = ReflectApplication08.class.getClassLoader().getResourceAsStream(" cn / ittext /day01/config.properties");Properties ps =new Properties();ps.load(resourceAsStream);String className = ps.getProperty("className");sop (className);*//*** 第三种方式 : 配置文件在 src 目录下的源文件地址中(classPath中),用类加载的方式加载资源文件 --> 简化版 : 相对路径** 分析 : 这种方式配置的路径是相对路径 --> 相对的是 src 目录下的当前源文件(.class类文件)地址**///通过类获取字节码文件,然后获取加载资源文件方法以此加载资源配置文件/* InputStream resourceAsStream = ReflectApplication08.class.getResourceAsStream("config.properties");Properties ps =new Properties();ps.load(resourceAsStream);String className = ps.getProperty("className");sop (className);*//*** 第四种方式 : 配置文件在 src 目录的其他目录下(不在classPath中),用类加载的方式加载资源文件 --> 简化版 : 绝对路径** 分析 : 这种方式配置的路径是绝对路径 ,是配置 bin以后的路径**/InputStream resourceAsStream = ReflectApplication08. class .getResourceAsStream( "/cn/ittext/day01/source/config.properties" );Properties ps = new Properties();ps .load( resourceAsStream );String className = ps .getProperty( "className" );sop ( className );}public static void sop(Object obj ){System. out .println( obj );}}
小结 :
1. Eclipse将src目录下的java文件自动编译成.class文件 放入 用户目录 , 将 src目录下的其他文件 原封不动的放入 用户目录2. 框架的配置文件都是放在classPath目录下,通过类加载器的方式进行加载获取的,对应到项目中就是放在 src目录下与源文件放在一起
3. 加载本包内的相关资源文件用相对路径,加载不同包内的相关资源文件用绝对路径
三. 由内省引出JavaBean的讲解
1 ) . 关于javaBean中内部属性的规则:
1.1 若get/set 之后单词的第二个字母是小的,则第一个字母变成小的 ; 案例 : Age --> age
[1] gettime --> time
[2] setTime -->time
[3] getCPU --> CPU
2 ) . 什么是内省? IntroSpector
2.1 描述 : 内省就是对内部进行检查,窥探底层细节,逻辑 ;
2.2 功能 : 对 javaBean进行操作 ;
3 ) . 什么是 javaBean?
3.1 描述 : javaBean是一种特殊的java类,内部是按照约定俗成的方式进行构建的,符合某种特定的规则
3.2 须知 : 一个javabean可以当作java类进行操作,而一个java类是不一定可当作javabean操作的
四. 对JavaBean的简单内省操作 --》这里有代码重构方式
1 ) . Demo: 完整版 未封装
package cn.ittext.day02;import java.beans.IntrospectionException;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class IntroSpectorTest{public static void main(String[] args ) throws NoSuchMethodException, SecurityException, IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{/**** 庖丁解牛 :操作 Javabean 的两种方式** 需求: 获取JavaBean中的属性Name,设置javaBean中的属性Age** 第一种 : 传统方式** 第二种 : 反射方式** 总结 :** 【1】 也就是通过反射的方式获取其读写方法而后进行调用** 【2】PropertyDescriptor类 可将其 属性名 与 对应类字节码文件关联访问其访问器方法****///传统方式/*JavaBeanDemo jbd =new JavaBeanDemo("张三",13); //实例化javaBean对象String name = jbd.getName(); //获取属性 namejbd.setAge(20); //设置属性ageint age = jbd.getAge(); //获取属性agesop (name+"::"+age); //输出验证*//*** 反射方式 --> 获取参数** 思路 :** 【1】 实例化对象** 【2】自定义想要属性的变量名** 【3】 将自定义属性变量名通过PropertyDescriptor与对应对象的字节码文件之关联起来访问其访问器方法** 【4】 获取其属性读的方法** 【5】用已有对象调用其方法**//* JavaBeanDemo jbd =new JavaBeanDemo("张三",13); //实例化javaBean对象String propertyName="name"; //自定义想要获取变量对应的属性名PropertyDescriptor pd =new PropertyDescriptor(propertyName, jbd.getClass()); //将属性名与与javaBean的字节码文件相关联访问其访问器方法Method readMethod = pd.getReadMethod(); //获取属性名对应的读方法Object retVal = readMethod.invoke( jbd ); //使用 jdb 调用读方法,读出数据sop (retVal);*//*** 反射方式 --> 设置参数** 思路 :** 【1】 实例化对象** 【2】自定义想要属性的变量名** 【3】 将自定义属性变量名通过PropertyDescriptor与对应对象的字节码文件之关联起来** 【4】 获取其属性写的方法** 【5】用已有对象调用其方法**/JavaBeanDemo jbd = new JavaBeanDemo( "张三" ,13); //实例化javaBean对象String propertyName = "name" ; //自定义想要获取变量对应的属性名PropertyDescriptor pd = new PropertyDescriptor( propertyName , jbd .getClass()); //将属性名与与javaBean的字节码文件相关联,访问其访问器方法Method writeMethod = pd .getWriteMethod();Object invoke = writeMethod .invoke( jbd , "王五" );sop ( jbd .getName());}public static void sop(Object obj ){System. out .println( obj );}}2 ) . Demo: 完整版 封装版 --》使用了代码重构
package cn.ittext.day02;import java.beans.IntrospectionException;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class IntroSpectorTestEnc{public static void main(String[] args ) throws NoSuchMethodException, SecurityException, IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{/**** 庖丁解牛 :** 需求: 获取JavaBean中的属性Name,设置javaBean中的属性Age*** 第二种 : 反射方式 -- 》对完整版的做了代码重构**** 总结 : 代码重构方式** 【1】 选中可进行封装的一堆代码,前提是保证其代码中没有常量存在** 【2】右击 -- 》 Refactor -- 》Extract Method -- 》 输入封装的方法名 -- 》而后 Ok 即可**** 附加 :我们还可以做接口的提取**/JavaBeanDemo jbd = new JavaBeanDemo( "张三" ,13); //实例化javaBean对象String propertyName = "name" ; //自定义想要获取变量对应的属性名Object retVal = getProperty ( jbd , propertyName ); //调用其自定义的获取资源的方法sop ( retVal );String vlaue = "王五" ;setProperty ( jbd , propertyName , vlaue );//调用其自定义的设置资源的方法sop ( jbd .getName());}//以下代码是通过代码重构的方式得来private static void setProperty(JavaBeanDemo jbd , String propertyName , String vlaue )throws IntrospectionException, IllegalAccessException, InvocationTargetException {PropertyDescriptor pd = new PropertyDescriptor( propertyName , jbd .getClass()); //将属性名与与javaBean的字节码文件相关联Method writeMethod = pd .getWriteMethod();Object invoke = writeMethod .invoke( jbd , vlaue );}private static Object getProperty(JavaBeanDemo jbd , String propertyName )throws IntrospectionException, IllegalAccessException, InvocationTargetException {PropertyDescriptor pd = new PropertyDescriptor( propertyName , jbd .getClass());Method readMethod = pd .getReadMethod();Object retVal = readMethod .invoke( jbd );return retVal ;}public static void sop(Object obj ){System. out .println( obj );}}
小结 :
1. javaBean对象也称为值对象,就是传递值的对象2. 所谓的简单操作就是用反射的方式读写 ,记得一个资源描述类 PropertyDescriptor 用来将自定义属性名与 类字节码文件相关联,以便于去字节码文件中查找对应的访问器方法
五
. 对javaBean的复杂内省操作
1 ) . Demo:
package cn.ittext.day02;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 IntroSpectorTest01{public static void main(String[] args ) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{/***** 需求 : 对 javabean 的内省操作,使用正向思维的方式** 分析:较上一章的反射方式,此章略显繁琐,但思路明确简单** 方法解析:*** beanInfo.getPropertyDescriptors(); 获取资源描述指 类的属性描述** beanInfo.getMethodDescriptors(); 获取方法描述是指类的方法描述** beanInfo.getBeanDescriptor(); 获取bean描述是指 类的描述*** 总结方法:** 【1】 Introspector 类 : 用来了解目标Java Bean支持的属性,事件和方法。** 【2】getBeanInfo(); 用来获取相关JavaBean的属性,事件和方法 与 已存在的 javabean 关联** 【3】getPropertyDescriptors(); 用来获取 javaBean中的详细的所有资源(属性)描述** 【4】getReadMethod(); 获取读取的方法** 【5】invoke(); 执行方法的方法**/JavaBeanDemo JBD = new JavaBeanDemo( "ZHANGSAN" , 20);String propertyName = "age" ; //定义好的想要获取属性的变量名getProperty ( JBD , propertyName );}//以下代码使用了代码重构,方法提取private static void getProperty(JavaBeanDemo JBD , String propertyName )throws IntrospectionException, IllegalAccessException, InvocationTargetException{BeanInfo beanInfo = (BeanInfo) Introspector. getBeanInfo ( JBD .getClass()); // 通过 Introspector 获取其 javabean 的属性方法信息PropertyDescriptor[] propertyDescriptors = beanInfo .getPropertyDescriptors(); //获取所有属性资源描述信息for (PropertyDescriptor pd : propertyDescriptors ) //迭代所有属性资源信息{String name = pd .getName(); //获取其资源信息名字if ( name .equals( propertyName )) //判断是否与自定义的属性变量名是否吻合,若吻合{Method readMethod = pd .getReadMethod(); // 则 获取其读取方法Object invoke = readMethod .invoke( JBD ); //通过 javabean 类调用其方法对象获取到想获取的值sop ( name + ":" + invoke ); //输出 值}}}public static void sop(Object obj ){System. out .println( obj );}}
六. 使用BeanUtils工具包操作JavaBean
1 ) . Demo:
package cn.ittext.day02;import java.lang.reflect.InvocationTargetException;import java.util.HashMap;import java.util.Map;public class IntroSpectorTest02{public static void main(String[] args ) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{/***** 庖丁解牛 : 通过工具类获取/设置一个javaBean中的属性** 第一种:获取** 第二种:设置** 小结 :** [1] BeanUtils工具类可设置/获取javaBean属性** [2]BeanUtils工具类可对javaBean进行级联设置/获取操作** [3] BeanUtils工具类与PropertyUtils都是对 javaBean属性进行操作,不一样的地方在于 BeanUtils对javaBean属性全部以字符串类型操作,而PropertyUtils是值的原类型进行操作** [4]BeanUtils工具类也可对map集合进行操作**///----------------------------------------------[1]JavaBeanDemo jbd = new JavaBeanDemo( "zhangsan" ,20);String propertyAge = "age" ;String propertyName = "name" ;String proName = BeanUtils. getProperty ( jbd , propertyName ); //获取相关属性sop ( "proName:::" + proName );BeanUtils. setProperty ( jbd , propertyAge , "22" ); //设置相关属性 , int 类型之所以加上"" ,一是因为主页面接受接受的是 字符串类型 ,而且 此方法有自动转型转换的功能String proAge = BeanUtils. getProperty ( jbd , propertyAge );sop ( "proAge:::" + proAge );//----------------------------------------------[2]String propertyBirths = "birthday.time" ;String proBirthBefor = BeanUtils. getProperty ( jbd , propertyBirths );sop ( "时间设置之前: proBirth:::" + proBirthBefor );BeanUtils. setProperty ( jbd , propertyBirths ,11100000);String proBirthEnd = BeanUtils. getProperty ( jbd , propertyBirths );sop ( "时间设置之后: proBirth:::" + proBirthEnd );//-------------------------------------------------[3]PropertyUtils pu = new PropertyUtils();String propertName = "name" ;PropertyUtils. setProperty ( jbd , propertName , "zhangsan" );String property = (String) PropertyUtils. getProperty ( jbd , propertName );sop ( property );//-------------------------------------------------[4]Map<String, String> map = new HashMap<>();map .put( "name" , "zhangsan" );BeanUtils. setProperty ( map , "name" , "李四" );sop ( map );}public static void sop(Object obj ){System. out .println( obj );}}
小结 :
1. 学会使用BeanUtils 工具类与 PropertyUtils 工具类 对javaBean进行操作
七. 框架总结 :
1 ) . 用资源配置文件的方式 反射 实例化对象
2 ) . 通过类加载器加载资源配置文件 ,关键的地方在于 配置文件的存放位置的不同会导致 使用 相对路径还是绝对路径的方式不同
3 ) . 通过 PropertyDescriptor类对javaBean进行属性访问器方法的 处理操作 ; 也可通过Introspector 类 的getBeanInfo() 方法对 javaBean进行资源方法类的操作
4 ) . 通过代码重构,方法提取的方式 对 臃肿的代码进行提取封装,以此简化代码
5 ). 站在巨人肩膀上学习变成,使用工具类 BeanUtils 与 PropertyUtils