学习笔记05—框架与反射初步
2013-04-12 16:10
295 查看
本篇中值得关注的时Properties类. 这个类实际上是Map的孙子。。。
Map有个实现类叫HashTable,与HashMap想相比是线程安全的,HashTable有个子类正是Properties
其关键字和值只能是String类型,经常被用来存储和访问配置信息。
1. 配置文件设置类名
以上篇HashCode相关中的代码为例,改用配置文件提供ArrayList和HashSet类名
右键点击项目名新建File,创建config.properties文件,写入
className=java.util.ArrayList
实际上是个键值对。
然后修改ReflectTest2类。
思路:
需要一个Properties类的对象,用其void load(InputStream inStream)方法载入一个输入流
这个输入流读取config.properties文件,
然后用其StringgetProperty(String key)方法“以键取值”,得到类名.具体代码如下:
这样就实现了某种程度上的“分离”,采用ArrayList还是HashSet只需在config.properties配置即可。
关于config.properties 的路径:
用方法得到工程的绝对路径,然后再根据工程内部相对路径找到文件。
2. 加载config.properties文件的另一种方式
在Eclipse中把config.properties文件拖到src目录下,这时Eclipse会自动将其复制到workspace的bin下
相应地,要更改路径
用1中的文件输入流的方式不仅可以读取文件,而且也可以写入文件。
用ClassLoader的方式适合读取配置文件。
但是这种写法仍然过于繁琐,下面是简化的写法,内部仍然用到了getClassLoader()
此时如果把文件移动到cn.itcast.day1.resources 包下面,就要写成
"resources/config.properties"
因为ReflectTest2.class从自己所在的包出发,即从day1文件夹下出发
如果从classpath下出发,则以"/"开头
"/cn/itcast/day1/resources/config.properties"
总结:
newFileInputStream(String path)需要动态计算项目真实目录然后加相对目录
classLoader.getResourceAsStream从classpath出发不加"/"
X.class.getResourceAsStream从classpath出发要加"/";如果文件路径跟X.class所在的包有关系则X.class所在目录出发
3. JavaBean
我们不知道JavaBean内部的属性到底叫什么,仅仅可以从get方法的名字上推断。
比如我们去买菠萝,菠萝卖家内部把菠萝叫做凤梨,而外面挂的牌子写着卖菠萝。
我们没有必要关心他们内部叫什么,我们只知道可以买到菠萝。
4. 用简单内省方式操作JavaBean
首先在ReflectPoint中添加x和y的setter和getter
新建测试类InspectorTest
可以用Eclipse的Refactor抽取方法。这一点已经在Eclipse使用技巧中的5.
Refactor中提过了。
将读写操作分别抽取成getProperties和setProperties方法。
最好用.getClass,不要用.class
总结:
关键之处在于new一个PropertyDescriptor,在构造方法中指明属性和对象
5. 对比: 另一种较为繁琐的操作方式
用Introspector.getBeanInfo(ClassbeanClass)取得BeanInfobeanInfo,
然后用beanInfo取得PropertyDescriptor[],
在这个数组中查找匹配propertyName的属性并做出处理。
下面代码写在getProperties方法里面
这中扫描的手段跟反射机制中的9.综合案例很相似。
综合案例中的代码片段回顾:
这种用beanInfo取得PropertyDescriptor[]的方式显然不如new PropertyDescriptor便捷。
6. BeanUtils
适用于操作JavaBeans的更加强大的工具类
由于在实际开发中对JavaBean的读写操作非常频繁,
人们做出了专门的工具类BeanUtils,用以对JavaBean进行操作。
首先导入beanutils和logging包。在工程下新建一个lib目录,复制两个jar包到其中。
分别右键点击它们Add to Build Path. 这样就可以使用BeanUtils了。
使用方法:
注意:
BeanUtils对JavaBean的属性进行读取和写入的时候都是用的String.
getProperty返回的是String,setProperty的时候可以用String类型。
BeanUtils可以进行类型的自动转换。
7. BeanUtils的另外一个特性是可以进行属性的级联操作。
如果一个对象的属性是个复合类型,BeanUtils可以把这个属性再当作JavaBean。
在ReflectPoint类里面增加一个Date类型的属性birthday,并添加其getter和setter.
birthday 属性本身又可以被当作JavaBean. Date类有setTime方法,就可以认为birthday有time属性。
于是可以这样操作:
这样运行会提示出错:
No bean specified
原因是birthday还没有实例化成为一个对象。
因此,在增加birthday属性的时候要初始化:
取得属性值:
8. BeanUtils的其他方法
void copyProperties(Object dest,Object orig) 把一个对象属性复制到另一个对象
Map describe(Object bean)把一个bean的属性转换为Map
void populate(Object bean, Map properties)把Map内容填充到bean中
9. BeanUtils操作Map对象
Java1.7关于Map定义的新语法 无法测试通过 暂时找不到解决办法
最可能的原因是这种新语法目前不被支持
Map map = {name :"zxx", age : 18};
这种写法跟Python中创建字典的写法很相似:
phone = {"Bob" : 1234,"Alice" : 5678}
有一种方法可以简便的创建Map,暂时先用这种方法,这种方法看起来也很奇妙:
关于这种写法,请参考fantaxy的空间_前庭 在Java_Map初始化中做了充分的说明,
在此向fantaxy致敬!
10.PropertyUtils和BeanUtils的区别
如果改为"8"则会提示argument type mismatch
总结:
PropertyUtils与BeanUtils的不同在于,
前者以属性本身的类型进行操作,而BeanUtils总是以字符串进行读写操作。
如果对BeanUtils的自作聪明不满意,需要准确的类型时,可以使用PropertyUtils.
Over.
Map有个实现类叫HashTable,与HashMap想相比是线程安全的,HashTable有个子类正是Properties
其关键字和值只能是String类型,经常被用来存储和访问配置信息。
框架初步
配置文件
1. 配置文件设置类名以上篇HashCode相关中的代码为例,改用配置文件提供ArrayList和HashSet类名
右键点击项目名新建File,创建config.properties文件,写入
className=java.util.ArrayList
实际上是个键值对。
然后修改ReflectTest2类。
思路:
需要一个Properties类的对象,用其void load(InputStream inStream)方法载入一个输入流
这个输入流读取config.properties文件,
然后用其StringgetProperty(String key)方法“以键取值”,得到类名.具体代码如下:
InputStream in = new FileInputStream("config.properties"); Properties props = new Properties(); props.load(in); // 不要忘记关闭流否则会造成系统资源不得释放 in.close(); String className = props.getProperty("className"); Collection c = (Collection) Class.forName(className).newInstance();
这样就实现了某种程度上的“分离”,采用ArrayList还是HashSet只需在config.properties配置即可。
关于config.properties 的路径:
用方法得到工程的绝对路径,然后再根据工程内部相对路径找到文件。
类加载器
2. 加载config.properties文件的另一种方式在Eclipse中把config.properties文件拖到src目录下,这时Eclipse会自动将其复制到workspace的bin下
相应地,要更改路径
// InputStream in = new FileInputStream("config.properties"); InputStream in =ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties"); // "cn/itcast/day1/config.properties"不要写成"/cn/itcast/... // 这里面的原因还不明确
用1中的文件输入流的方式不仅可以读取文件,而且也可以写入文件。
用ClassLoader的方式适合读取配置文件。
但是这种写法仍然过于繁琐,下面是简化的写法,内部仍然用到了getClassLoader()
// 下面的写法可以只写文件名 // 因为文件位于与ReflectTest2.class同一包下(相对于包的路径) InputStream in = ReflectTest2.class.getResourceAsStream("config.properties");
此时如果把文件移动到cn.itcast.day1.resources 包下面,就要写成
"resources/config.properties"
因为ReflectTest2.class从自己所在的包出发,即从day1文件夹下出发
如果从classpath下出发,则以"/"开头
"/cn/itcast/day1/resources/config.properties"
总结:
newFileInputStream(String path)需要动态计算项目真实目录然后加相对目录
classLoader.getResourceAsStream从classpath出发不加"/"
X.class.getResourceAsStream从classpath出发要加"/";如果文件路径跟X.class所在的包有关系则X.class所在目录出发
IntroSpector和JavaBean
3. JavaBean我们不知道JavaBean内部的属性到底叫什么,仅仅可以从get方法的名字上推断。
比如我们去买菠萝,菠萝卖家内部把菠萝叫做凤梨,而外面挂的牌子写着卖菠萝。
我们没有必要关心他们内部叫什么,我们只知道可以买到菠萝。
4. 用简单内省方式操作JavaBean
首先在ReflectPoint中添加x和y的setter和getter
新建测试类InspectorTest
public staticvoidmain(String[] args) throws Exception { ReflectPoint p1 = new ReflectPoint(3, 5); String propertyName = "x"; /* * 普通方法缺点在于手动写出getX 不够智能 */ Method method = p1.getClass().getMethod("getX"); Object retVal = method.invoke(p1); System.out.println(retVal); /* * 内省方法 */ PropertyDescriptor pd = new PropertyDescriptor(propertyName, p1.getClass()); Object retVal2 = pd.getReadMethod().invoke(p1); System.out.println(retVal2); /* * set对象的值 */ pd.getWriteMethod().invoke(p1, 7); retVal2 = pd.getReadMethod().invoke(p1); System.out.println(retVal2); }
可以用Eclipse的Refactor抽取方法。这一点已经在Eclipse使用技巧中的5.
Refactor中提过了。
将读写操作分别抽取成getProperties和setProperties方法。
最好用.getClass,不要用.class
private staticvoidsetProperties(Object p1, String propertyName, Object value) throws... { PropertyDescriptor pd2 = new PropertyDescriptor(propertyName, p1.getClass()); pd2.getWriteMethod().invoke(p1, value); } private staticObject getProperties(Object p1, String propertyName) throws...{ PropertyDescriptor pd1 = new PropertyDescriptor(propertyName, p1.getClass()); Object retVal2 = pd1.getReadMethod().invoke(p1); returnretVal2; }
总结:
关键之处在于new一个PropertyDescriptor,在构造方法中指明属性和对象
new PropertyDescriptor(propertyName, p1.getClass());
5. 对比: 另一种较为繁琐的操作方式
用Introspector.getBeanInfo(ClassbeanClass)取得BeanInfobeanInfo,
然后用beanInfo取得PropertyDescriptor[],
在这个数组中查找匹配propertyName的属性并做出处理。
下面代码写在getProperties方法里面
// 取得beanInfo BeanInfo beanInfo = Introspector.getBeanInfo(p1.getClass()); // 取得PropertyDescriptor的数组 PropertyDescriptor[] pds =beanInfo.getPropertyDescriptors(); Object retVal2 = null; // 遍历数组查找匹配的属性 for (PropertyDescriptor pd : pds) { if(pd.getName().equals(propertyName)) { // 得到getter 激发对象使其调用 retVal2 =pd.getReadMethod().invoke(p1); break; } } return retVal2;
这中扫描的手段跟反射机制中的9.综合案例很相似。
综合案例中的代码片段回顾:
Field[] fields = obj.getClass().getFields(); // 对所有字段进行迭代,判断是否是String类型的,如果是则进一步处理 for (Field field : fields) { // 因为字节码只有一份,所以用==,用equals会造成语义不明确 if (field.getType() == String.class) { String oldStr = (String)field.get(obj); String newStr = oldStr.replace('b', 'a'); field.set(obj, newStr); } }
这种用beanInfo取得PropertyDescriptor[]的方式显然不如new PropertyDescriptor便捷。
BeanUtils操作JavaBean
6. BeanUtils适用于操作JavaBeans的更加强大的工具类
由于在实际开发中对JavaBean的读写操作非常频繁,
人们做出了专门的工具类BeanUtils,用以对JavaBean进行操作。
首先导入beanutils和logging包。在工程下新建一个lib目录,复制两个jar包到其中。
分别右键点击它们Add to Build Path. 这样就可以使用BeanUtils了。
使用方法:
BeanUtils.getProperty(p1,propertyName); BeanUtils.setProperty(p1,propertyName, "9");
注意:
BeanUtils对JavaBean的属性进行读取和写入的时候都是用的String.
getProperty返回的是String,setProperty的时候可以用String类型。
BeanUtils可以进行类型的自动转换。
7. BeanUtils的另外一个特性是可以进行属性的级联操作。
如果一个对象的属性是个复合类型,BeanUtils可以把这个属性再当作JavaBean。
在ReflectPoint类里面增加一个Date类型的属性birthday,并添加其getter和setter.
birthday 属性本身又可以被当作JavaBean. Date类有setTime方法,就可以认为birthday有time属性。
于是可以这样操作:
BeanUtils.setProperty(p1, "birthday.time","111");
这样运行会提示出错:
No bean specified
原因是birthday还没有实例化成为一个对象。
因此,在增加birthday属性的时候要初始化:
private Date birthday= newDate();
取得属性值:
System.out.println("beanutils getting: " + BeanUtils.getProperty(p1, "birthday.time"));
8. BeanUtils的其他方法
void copyProperties(Object dest,Object orig) 把一个对象属性复制到另一个对象
Map describe(Object bean)把一个bean的属性转换为Map
void populate(Object bean, Map properties)把Map内容填充到bean中
9. BeanUtils操作Map对象
Java1.7关于Map定义的新语法 无法测试通过 暂时找不到解决办法
最可能的原因是这种新语法目前不被支持
Map map = {name :"zxx", age : 18};
这种写法跟Python中创建字典的写法很相似:
phone = {"Bob" : 1234,"Alice" : 5678}
有一种方法可以简便的创建Map,暂时先用这种方法,这种方法看起来也很奇妙:
关于这种写法,请参考fantaxy的空间_前庭 在Java_Map初始化中做了充分的说明,
在此向fantaxy致敬!
Map map = new HashMap() { { put("name", "zxx"); put("age", "25"); } };
BeanUtils.setProperty(map, "name", "jean"); System.out.println(BeanUtils.getProperty(map, "name"));
10.PropertyUtils和BeanUtils的区别
PropertyUtils.setProperty(p1,propertyName, 8); System.out.println(PropertyUtils.getProperty(p1,propertyName));
如果改为"8"则会提示argument type mismatch
总结:
PropertyUtils与BeanUtils的不同在于,
前者以属性本身的类型进行操作,而BeanUtils总是以字符串进行读写操作。
如果对BeanUtils的自作聪明不满意,需要准确的类型时,可以使用PropertyUtils.
Over.
相关文章推荐
- CCIE学习笔记框架——网络的初步了解
- php学习笔记(三十四)smarty框架的初步使用和注意事项
- onvif学习笔记5:onvif框架代码初步了解
- 0034 Java学习笔记-反射-初步2-操作对象
- .Net 初步学习笔记之一——.Net 平台与.Net FrameWork框架的关系
- 0033 Java学习笔记-反射-初步1
- Python Web开发 之Django框架入门学习笔记(一)——安装和初步使用
- eclipse初步学习笔记(快捷键 运行调试 junit测试框架)
- spring mvc 初步接触学习笔记
- 学习笔记5-集合框架
- 黑马程序员—Java基础加强学习笔记之枚举&反射
- LungoJS框架学习笔记——列表
- 反射学习笔记(二) - - 暴力反射 - -
- (原创)c#学习笔记10--定义类成员05--部分方法定义
- Java学习笔记--运用反射
- 学习SSM框架笔记四:Spring注解
- (原创)c#学习笔记08--面向对象编程简介02--OOP技术05--运算符重载
- hadoop2.7.2学习笔记05-hadoop文件系统API定义-hadoop文件系统模型
- 关于Collection框架的学习笔记
- Flask框架学习笔记(一)安装篇(windows安装与centos安装)