JavaBean与Introspector

反射和内省操作很多时候都是在以后要做框架的时候作用非常大。
    现在你学的是面向对象编程,即:你所写代码都能够找到对应的类或接口,找到具体的方法写出对应的代码。
    但是以后学面向抽象编程的时候,即:我们所写的代码完全抽象,比如我们写的框架所要面向的类或方法目前并没有的,而是以后别人用我们的框架写出来的类。但是我们又怎么调用去他们的类get/set方法呢?所以这个时候要用到反射和内省进行抽象编程。

/*
JavaBean与内省(Introspector):
1.JavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法
主要用于访问私有字段,且方法名符合某种命名规则.
2.如果在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例
通常称之为值对象(Value Object).这些信息在类中用私有字段来存储,如果读取货设置这些字段的值
则需要通过一些相应的方法来访问,这些方法该如何命名?
JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量.如果方法
名为setId,意为设置id,至于你存到哪个变量上,用管吗?getId意为获取id,至于从哪个变量上得到的,用管吗?
去掉set前缀后,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小写.
setId属性名->id
isLast属性名->last
setCPU属性名->CPU
总而言之:一个类被当做JavaBean使用时,JavaBean的属性是根据方法名推断出来的
它根本看不到java类内部的成员变量 一个符合JavaBean特点的类可以被当做普通类一样进行使用,但把它当做JavaBean用肯定需要带来一些额外的好处
好处:
1.在JavaEE开发中,经常使用JavaBean.很多环境要求按JavaBean方式进行操作
2.JDK提供了对JavaBean进行操作的一些API,这套API就称为内省.
*/
//eclipse 4.3下自动生成getter和setter方法
//JavaBean的属性是由getter或setter方法决定
//只要含有其中的一个方法就是JavaBean的属性
//User类继承Object的方法getClass,因此还有一个属性为class
class User{
private String userName;//字段
private String uName;//字段
private String CPU;
private String controlProcessUnited;
private int x; public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getuName() {
return uName;
}
public void setuName(String uName) {
this.uName = uName;
}
public String getCPU() {
return CPU;
}
public void setCPU(String cPU) {
CPU = cPU;
}
public String getControlProcessUnited() {
return controlProcessUnited;
}
public void setControlProcessUnited(String controlProcessUnited) {
this.controlProcessUnited = controlProcessUnited;
} }

对JavaBean内省操作:

用一个测试类:Car

package com.itheima.day2;

import java.util.Date;

public class Car {
private String color;
private int number;//轮胎个数
private Date birthday=new Date();//为了测试 设置级联属性
public Car(String color, int number) {
super();
this.color = color;
this.number = number;
}
public String getColor(){
return color;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void setColor(String color) {
this.color = color;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
} }
package com.itheima.day2;
import java.lang.reflect.Method;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor; public class IntrospectorDemo { public static void main(String[] args)throws Exception{
// TODO 自动生成的方法存根
//方式一:使用反射操作JavaBean
//获取颜色->color->color有一个单词第二个字母小写->推断出方法名getColor
Car car=new Car("红色",4);
Method method=car.getClass().getMethod("getColor");
Object retVal=method.invoke(car);
System.out.println(retVal);//"红色" //方式二:使用内省操作JavaBean->不用再推断方法名
PropertyDescriptor pd=new PropertyDescriptor("color",car.getClass());//第一个参数属性名,第二个参数把哪一个类当成JavaBean类
method=pd.getReadMethod();//将获取到的getColor方法封装成Method对象
retVal=method.invoke(car);
System.out.println(retVal);//"红色" method=pd.getWriteMethod();//将获取到的setColor方法封装成Method对象
method.invoke(car,"黑色");
System.out.println(car.getColor());//验证是否改掉//"黑色" //测试封装后的方法
System.out.println(getProperty("number",car));//
setProperty("number",car,10);
System.out.println(car.getNumber());//
} //对上面的操作步骤进行封装提高复用性
public static Object getProperty(String property,Object obj) throws Exception{//获取指定对象的属性值
PropertyDescriptor pd=new PropertyDescriptor(property,obj.getClass());
Method method=pd.getReadMethod();
return method.invoke(obj); /*//方法二:
BeanInfo bi=Introspector.getBeanInfo(obj.getClass());//在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件,描述目标 bean 的 BeanInfo 对象。
PropertyDescriptor[] pdArrs=bi.getPropertyDescriptors();//获取到该JavaBean中所有属性信息,BeanInfo没有获取单个属性的方法
for(PropertyDescriptor pdArr : pdArrs)
if(pdArr.getName().equals(property)){//获取到属性描述的属性名称(getName),遍历
Method method=pdArr.getReadMethod();
return method.invoke(obj);
}
return null;*/ }
public static void setProperty(String Property,Object obj,Object value)throws Exception{
PropertyDescriptor pd=new PropertyDescriptor(Property,obj.getClass());
Method method=pd.getWriteMethod();
method.invoke(obj,value);
} }

使用开源工具BeanUtils来操作JavaBean:

/*
使用开源BeanUtils来更方便操作JavaBean
1.从http://commons.apache.org/beanutils/下载commons-beanutils-1.8.3-bin.zip
2.将其中的.jar导入工程
3.不采用BuildPath->添加外部归档方式导入工程,这样做.jar并不在工程目录下(例如在d:\下)
一旦将工程拷贝到其它机器下,还需要把该.jar拷贝到d:\下,不然用不了
解决方式:在工程下新建lib文件夹->将.jar拷贝到lib下->Build Path */
/*
public static String getProperty(Object bean,String name)
throws IllegalAccessException,
InvocationTargetException,
NoSuchMethodException
public static void setProperty(Object bean,String name,Object value)
throws IllegalAccessException,
InvocationTargetException*/ public class BeanUtilsDemo { public static void main(String[] args)throws Exception {
// TODO 自动生成的方法存根
Car car=new Car("black",20); //使用BeanUtils来set/get属性
String number=BeanUtils.getProperty(car,"number");//获取car对象color属性的值,注意返回值固定为String
BeanUtils.setProperty(car,"color","red");//设置car对象number属性的值为4
BeanUtils.setProperty(car,"number","2");//传入2(自动装箱,内部需要拆箱)或"2"均可,"2"内部涉及到从String->int转换
System.out.println(car.getColor()+" "+car.getNumber()+"\n"); //级联属性设置与获取
BeanUtils.setProperty(car,"birthday.time","1000");//在Date类中一个public void setTime(long time)方法->属性time
//通俗例子:设置person.head.face.eye.color
System.out.println(BeanUtils.getProperty(car,"birthday.time")+"\n"); //JavaBean与Map相互转换
Map map=BeanUtils.describe(car);//会将JavaBean中 所有属性值 存入到Map中,前提是该属性值有对应get方法
System.out.println(map);//里面还有一个属性为字节码文件对象,也就是指定的JavaBean类
map=new HashMap();
map.put("color","blue");
map.put("number",2);
map.put("birthday.time",200);
BeanUtils.populate(car, map);//填充:将map中key对应javabean中的property,将其value赋给property
System.out.println(car.getColor()+" "+car.getNumber());
System.out.println(BeanUtils.getProperty(car,"birthday.time")+"\n"); //PropertiesUtils工具类
PropertyUtils.setProperty(car,"number",13);//属性值的类型必须和Car中number类型一致均为int
Object obj=PropertyUtils.getProperty(car, "number");
System.out.println(obj+" "+obj.getClass().getName());//说明上面的getProperty以Integer类型返回
} }
/*
不导入commons-logging-1.1.3.jar之前的运行结果:
Exception in thread "main" java.lang.NoClassDefFoundError:
org/apache/commons/logging/LogFactory
相当于有了电视机,但遥控器是第三方->电视机没法用
需要导入遥控器->下载commons-logging(通用日志)并build path*/
package cn.itcast.feature;
2:
3: import java.lang.reflect.InvocationTargetException;
4: import java.text.ParseException;
5: import java.text.SimpleDateFormat;
6: import java.util.Date;
7:
8: import org.apache.commons.beanutils.BeanUtils;
9: import org.apache.commons.beanutils.ConversionException;
10: import org.apache.commons.beanutils.ConvertUtils;
11: import org.apache.commons.beanutils.Converter;
12: import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
13: import org.junit.Test;
14:
15: /*
16: 虽然使用BeanUtils简化了代码量
17: 但是BeanUtils默认只能帮你进行八大基本类型间的转换或
18: String到八大基本类型转换.
19: 如果我需要用到String->Date的转换,需要我们自定义转换器
20: */
21: public class CustomConvert {
22: private Person p=new Person();
23: @Test
24: public void convertTest_1() throws IllegalAccessException, InvocationTargetException{
25: BeanUtils.setProperty(p,"birthday","1980-3-1");
26: System.out.println(p.getBirthday());
27: }
28:
JUnit测试:
2.这时候我们需要自定义转换器完成String->Date
1: @Test
2: public void convertTest_2() throws IllegalAccessException, InvocationTargetException{
3: ConvertUtils.register(//注册一个自定义转换器完成String->Date转换
4: new Converter() {
5: @Override
6: public Object convert(Class type, Object value) {
7: // TODO Auto-generated method stub
8: if (value == null)
9: return null;
10: if (!(value instanceof String))
11: throw new ConversionException("不支持从"
12: + value.getClass().getName() + "到"
13: + type.getName() + "的转换");
14: String valueStr = (String) value;
15: if ((valueStr = valueStr.trim()).equals(""))// 去除字符串首尾的空格,同时判断是否是空串
16: return null;
17:
18: // 开始转换工作,以上做的判断完全为了程序的健壮性
19: SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
20: try {
21: return sdf.parse(valueStr);// 该方法有异常声明但是我不能在convert方法上进行声明,只能try...catch
22: // 因为该匿名子类复写的Converter中的convert方法上没有任何异常声明
23: } catch (ParseException e) {
24: // TODO Auto-generated catch block
25: throw new RuntimeException(e);
26: }
27:
28: }
29:
30: }, Date.class);
31: BeanUtils.setProperty(p,"birthday","1980-3-1");
32: System.out.println(p.getBirthday());
33: }
3.如果把BeanUtils.setProperty(p,"birthday","1980-3-1");换成BeanUtils.setProperty("birthday",1980-3-1);不能通过测试:
4.使用已提供的Sting->Date的转换器:
 @Test
2: public void convertTest_3() throws IllegalAccessException, InvocationTargetException{
3: //使用API提供的转换器:DateLocaleConverter
4: ConvertUtils.register(new DateLocaleConverter(),Date.class);
5: BeanUtils.setProperty(p,"birthday","1980-3-1");
6: System.out.println(p.getBirthday());
7:
8: //但是该转换器有Bug,那就是传入一个空串
9: BeanUtils.setProperty(p,"birthday","");
10: System.out.println(p.getBirthday());
11: }
 
 
5.最后来看下throw new RuntimeException(e);打印的异常信息:
1:   @Test
2: //throw new RuntimeException(Throwable cause);
3: /*用指定的原因和详细消息 (cause==null ? null :cause.toString())
4: 构造一个新的运行时异常(它通常包含类和 cause 的详细消息)。
5: */
6: //下面我们故意让parse抛出ParseException看下打印信息
7: public void ParseExceptionTest(){
8: try {
9: System.out.println(new SimpleDateFormat("yyyy/MM/dd").parse("2014-1-17"));
10: } catch (ParseException e) {
11: // TODO Auto-generated catch block
12: throw new RuntimeException(e);
13: }
14: }

JavaBeans与内省(Introspector)的更多相关文章

  1. 【小家Spring】聊聊Spring中的数据绑定 --- BeanWrapper以及内省Introspector和PropertyDescriptor

    #### 每篇一句 > 千古以来要饭的没有要早饭的,知道为什么吗? #### 相关阅读 [[小家Spring]聊聊Spring中的数据转换:Converter.ConversionService ...

  2. 聊聊Java内省Introspector

    前提 这篇文章主要分析一下Introspector(内省,应该读xing第三声,没有找到很好的翻译,下文暂且这样称呼)的用法.Introspector是一个专门处理JavaBean的工具类,用来获取J ...

  3. 内省(introspector)------>JavaBean

    内省(introspector)------>JavaBean    1.问什么要学内省?        开发框架时,经常需要Java对象的属性来来封装程序的数据,每次使用反射技术完成此操作过于 ...

  4. 内省(Introspector)

    内省(Introspector) 是Java 语言对 JavaBean 类属性.事件的一种缺省处理方法 目的:主要用于传递数据信息,这种类中的方法主要用于访问私有的字段(且方法名符合某种命名规则) p ...

  5. 深入理解Java:内省(Introspector)

    深入理解Java:内省(Introspector) 内省(Introspector) 是Java 语言对 JavaBean 类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类,主要用于传 ...

  6. Java:内省(Introspector)

    内省(Introspector) 是Java 语言对 JavaBean 类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且 ...

  7. Java 内省(Introspector)深入理解

    Java 内省(Introspector)深入理解 一些概念: 内省(Introspector) 是Java 语言对 JavaBean 类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类 ...

  8. Java 内省(Introspector)和 BeanUtils

    人生若只如初见,何事秋风悲画扇. 概述 内省(Introspector) 是Java 语言对 JavaBean 类属性.事件的一种缺省处理方法. JavaBean是一种特殊的类,主要用于传递数据信息, ...

  9. (转载)深入理解Java:内省(Introspector)

    本文转载自:https://www.cnblogs.com/peida/archive/2013/06/03/3090842.html 一些概念: 内省(Introspector) 是Java 语言对 ...

随机推荐

  1. QGis C++ 开发之创建临时图层并添加要素

            开发环境:Win10 + VS2010 + Qt 4.8.6 + QGis 2.14.4 其实本文实现的功能类似于QGis中“添加文本数据图层”的一个简化版,本文不会涉及到对话框的使用 ...

  2. C#自定义控件开发

    自定义控件开发 一般而言,Visual Studio 2005中自带的几十种控件已经足够我们使用了,但是,在一些特殊的需求中,可能需要一些特殊的控件来与用户进行交互,这时,就需要我们自己开发新的.满足 ...

  3. Python2.7-Queue

    Queue 模块,python3中为queue,一般和threading模块同时使用,用于处理多任务队列,模块定义了3种队列类,先进先出(FIFO),后进先出(LIFO),优先级队列 Queue.Qu ...

  4. Android failed to start daemon

    异常描述:在Eclipse中运行Android项目时Console中出现: The connection to adb is down, and a severe error has occured. ...

  5. HDU 3592 World Exhibition(线性差分约束,spfa跑最短路+判断负环)

    World Exhibition Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  6. jqgrid 配置分页大小及下拉项

    如何配置分页大小的下拉项?显示效果如下: 通过 rowNum 来设置默认分页大小 通过 rowList 来设置分页下拉.   rowList 的值为一个数组,比如:[10,20,30] $(" ...

  7. bitmap过大无法显示图片的问题 - z

    public Bitmap ratio(Bitmap image, float pixelW, float pixelH) {Bitmap bitmap = null;try {ByteArrayOu ...

  8. Huploadify V2.1+ SpringMVC上传文件的实现

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  9. EZ 2017 12 17初二初三第一次膜你赛

    以后平时练习还是写一写吧. (题目搞来搞去太烦了,直接PDF存起来) T1 水题(???),主要是数据水,正解是设一个阙值,然而根本没人打.(暴力出奇迹) CODE #include<cstdi ...

  10. 【Qt】QLabel实现的圆形图像

    本篇只描述圆形图像的两种实现方式,动态阴影边框如下: [Qt]QLabel之动态阴影边框 目前实现的效果如下: 左右两边实现的方式不同: 右边比较简单 min-width: 100px; max-wi ...