JAVA基础 内省机制

注:本文主要记录自 兄弟连_马剑威 JavaSE第三季 第49讲 内省机制

1、JavaBean的概念

  • 什么是JavaBean?
  • Bean理解为组件的意思,JavaBean就是Java组件,在广泛的理解就是一个类,对于组件来说,关键在于要具有“能够被IDE构建工具侦测其属性和事件”的能力,通常在Java中
一个JavaBean要具备这样的命名规则:
  1. 对于一个名称为xxx的属性,通常你要写两个方法:getXxx() 和 setXxx() .任何浏览这些方法的工具,都会把get或set后面的第一个字母自动转换为小写。
  2. 对于布尔型属性,可以使用以上get和set方式,不过也可以把get替换成is
  3. Bean的普通方法不必遵循以上命名规则,不过他们必须是public的
  4. 对于事件,要使用Swing中处理监听器的方式。如addWindowListener,removeWindowListener
2、内省的基本概念
  • 内省(IntroSpector)是Java语言对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getName,setName来得到其值或者设置新的值。
  • 通过getName/setName来访问name属性,这就是默认的规则。
  • Java中提供了一套API用来访问某个属性的getter/setter方法,通过这些API可以使你不需要理解这个规则,这些API存放于包java.beans中,一般的做法是通过类Introspector的getBeanInfo方法来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法。

3、IntroSpector相关API
1、Introspector类:
Introspector类为通过工具学习有关受目标JavaBean支持的属性、事件和方法的知识提供了一个标准方法。
static BeanInfo getBeanInfo(Class<?> beanClass)
在JavaBean上进行反省,了解其所有属性、公开的方法和事件

2、BeanInfo类
该类实现此BeanInfo接口并提供有关其bean的方法、属性、事件等显式信息。
MethodDescriptor[] getMethodDescriptors()
获得 beans MethodDescriptor
PropertyDescriptor[] getPropertyDescriptors()
获得beans PropertyDescriptors

3、PropertyDescriptor类:
PropertyDescriptor描述JavaBean通过一对存储器方法导出的一个属性
Method getReadMethod()
获得应该用于读取属性值的方法
Method getWriteMethod()
获得应该用于写入属性值的方法 

4、MethodDescriptor类:
MethodDescriptor 描述了一种特殊方法
即Java Bean支持从其他组件对其进行外部访问
Method getMethod()
获得此MethodDescriptor封装的方法

实例:
/**
 * javaBean
 *
 */
public class Dog {
	private int age;
	private String name;

	public int getAge() {
		return age;
	}

	public String getName() {
		return name;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public void setName(String name) {
		this.name = name;
	}

}

/**
 * 内省
 *
 */
public class IntroSpectorDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
//		Dog dog=new Dog();//使用者与被使用者耦合
		//不耦合可以使用工厂模式
		Dog dog=DogFactory.getDog("dog");
		
	}

}

/**
 * 工厂类
 *
 */
public class DogFactory {
	public static Dog getDog(String dogname) {
		if("dog".equals(dogname)){
			return  new Dog();//此处也耦合
		}
		return null;
	}
}

但在如上的工厂类里,仍是会用到  new Dog();产生耦合
所以需要采取另外的途径,
如在反射中的:Class.forName("class的全路径")

创建配置文件 bean.properties,使用配置文件的目的是修改方便,相比定义在类中的静态参数而言,当某天代码参数发生变化时,只要修改配置文件中的参数,重启系统即可。而在代码中的参数修改则需要重新修改源码,编译,替换。【注:配置文件如果要正常显示中文,需要将配置文件的编码格式更改为:utf-8】
<pre name="code" class="java">#配置javaBean的全名
dog=IntroSpectorDemo.Dog
dog.name=小白
dog.age=4
 
在工厂类中通过读取配置文件信息,并利用内省机制生成Dog实例
/**
 * 工厂类
 * @author zhan414
 *
 */
public class DogFactory {
	
	private static Properties config=new Properties();//处理properties文件的工具类,负责读写属性文件
	static{
		//读取属性文件
		InputStream inputStream=Thread.currentThread().getContextClassLoader().getResourceAsStream("bean.properties");
		//加载属性文件
		try {
			config.load(inputStream);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public static Dog getDog(String dogname){
		//从Properties对象中根据key获取value
		String className =config.getProperty("dog");
		try {
			//根据类全名获取类信息对象Class对象
			Class dogClass = Class.forName(className);
			//实例化对象
			Dog dog=(Dog) dogClass.newInstance();
			//内省:获取bean信息
			BeanInfo beanInfo=Introspector.getBeanInfo(dogClass);
			//通过bean信息获取所有属性描述器,数组
			PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors();
			//循环遍历属性描述器
			for (PropertyDescriptor propertyDescriptor : pds) {
				if ("name".equals(propertyDescriptor.getName())) {//判断是否是name属性
					String nameValue=config.getProperty("dog.name");
					//通过属性描述器获取该属性的写操作(set方法)
					Method method=propertyDescriptor.getWriteMethod();
					//在dog对象上调用方法
					method.invoke(dog, nameValue);
				}else if ("age".equals(propertyDescriptor.getName())) {
					String  ageValue=config.getProperty("dog.age");
					Method method=propertyDescriptor.getWriteMethod();//内省
					method.invoke(dog, Integer.valueOf(ageValue));
				}
				//返回对某属性的method对象,相比反射要方便许多
				//eg:Method setNameMethod=personClass4.getMethod("setName", String.class);  
			    //	 setNameMethod.invoke(p5, "小花");//相当于 p5.setName("小花");  
			}
			return dog;
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IntrospectionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
}
测试:
public class IntroSpectorDemo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Dog dog=DogFactory.getDog("dog");
		System.out.println("dog.name= "+dog.getName()+" , dog.age= "+dog.getAge());
	}
}
输出:
dog.name= 小白 , dog.age= 4
可以看到name为乱码,这是因为配置文件中 dog.name的值为中文,未转成 unicode格式
解决方法:修改DogFactory中的properties文件输入静态块,配置输入流的编码格式,如下:
	static {
		try {
			// 读取属性文件
			InputStream inputStream = Thread.currentThread()
					.getContextClassLoader()
					.getResourceAsStream("bean.properties");
			BufferedReader bf = new BufferedReader(new InputStreamReader(
					inputStream, "utf-8"));
			// 加载属性文件
			config.load(bf);
			//关闭流
			inputStream.close();
			bf.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
修改后便可输出中文







eclipse properties文件中文格式使用配置:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值