JavaSE 拾遗(16)——JavaSE 高新技术基础增强...反射

news/2024/5/19 6:59:10 标签: java, javase, 反射

反射的作用

反射的作用总结起来就一个:倒转了目标类和客户类的依赖关系。
以前我们设计程序,客户类要么依赖于目标类,要么依赖于目标类的接口。因为目标类是作为工具提供给客户类使用的,根据 java 基本语法规则,要使用某个类,必须知道该类提供的接口。有了反射之后,我们就可以方便是使用反射来实现框架,解除框架中对于我们写的类——目标类,的依赖关系。

反射的概念和实现原理


Reflection 是Java被视为动态(或准动态)语言的一个关键性质。反射就是 把 JVM 通过符号引用动态解析 java 类的字节码的能力映射成为各种 Java 类的成分类的机制,通过这个机制,java 把 JVM 动态解析符号引用的功能封装为各种 API 类公开给我们使用,这个机制允许我们可以 于运行时加载、探知、使用,编译期间完全未知的classes程序在运行时通过 Reflection APIs 取得任何一个 class 的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces(例如Serializable),也包括 fields 和 methods 的所有信息,并 于运 行时改变该类的对象的 fields 内容或调用该类或者该类对象的 methods。这种动态获取类的信息以及动态调用对象的方法的功能就是Java 语言的反射(Reflection)机制。

以前我们使用java的时候都是在编译阶段之前定义好类和对象的结构,比如类名、成员名、类的结构、成员函数的结构等等,并在编译阶段之前的源代码中用这些我们自己已经明确知道的东西来使用这些类和类的对象。反射和这个思想刚好不同。反射到底反在什么地方,我认为在使用反射之前我们写的程序,是我们已知某个类提供的接口了,然后我们创建这个类的对象,使用这个类的功能,在这个过程中,编译器和 jvm 在执行我们这个程序的时候,编译器只负责把我们使用时关于类的符号原封不动的保存下来,jvm 在执行这里的时候,再实现符号引用的动态解析。使用反射却恰好相反,我们使用这个类,只知道类名,其具体的信息完全不知道,我们需要通过 jvm 加载这个类之后(如果这个类没有加载我们使用 APIs 里面 ClassLoader 的 defineClass 的方法来加载一个通过字符串传递的类名的类),通过反射相关的 APIs 来给这个类创建 Class 类型的对象,在通过相关 APIs 获取这个类相关的信息,再通过反射相关的 APIs 来使用这个类提供的信息。这就是反射,反就反在我们使用类的信息是在编译器阶段还是在运行时阶段。

Java 反射机制主要提供了以下功能:
  • 在运行时判断任意一个对象所属的类。
  • 在运行时构造任意一个类的对象。
  • 在运行时判断任意一个类所具有的成员变量和方法。
  • 在运行时调用任意一个对象的方法。
在 JDK 中,主要由以下类来实现 Java 反射机制,这些类都位于 java.lang 或者 java.lang.reflect 包中:
  • Class类:代表一个类。
  • Field 类:代表类的成员变量(成员变量也称为类的属性)。
  • Method类:代表类的方法。
  • Constructor 类:代表类的构造方法。
  • Array类:提供了动态创建数组,以及访问数组的元素的静态方法。


透析反射的基础_Class 类

java.lang.Object
     java.lang.Class<T>

Class 类十分特殊。它和一般 class 一样继承自 Object,其实体用以表达 Java 程序运行时的 class 和 interface,也用来表达 enum、array、primitive Java types
(boolean, byte, char, short, int, long, float, double)以及关键词 void。当一个 class 被加载,或当加载器(class loader)的 defineClass() 被 JVM 调用,JVM 便自动产生一个Class object。
Class 类是 JVM 为提供反射机制,而提供的用来描述 class 字节码 的类,每一个 class 字节码都是一个 Class 对象,JVM 通过 Class 的功能函数,提供给我们动态解析 class 字节码的能力,通过 Class 类对象可以获取成员变量、成员方法、接口、超类、构造方法等,Class 类是 Reflection API 中的核心类,它有以下常用方法
  • getName():获得类的完整名字。
  • getFields():获得类的public类型的属性。
  • getDeclaredFields():获得类的所有属性。
  • getMethods():获得类的public类型的方法。
  • getDeclaredMethods():获得类的所有方法。
  • getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
  • getConstructors():获得类的public类型的构造方法。
  • getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
  • getSuperClass():
  • getInterface():
  • getModifiers() :
  • getAnnotations() :
  • getClassLoader() :
  • newInstance():通过类的不带参数的构造方法创建这个类的一个对象。

Class 是 Object 类的子类,所以 Class 对象也是 Object 对象,Class 对象调用 getClass() 方法会返回自己的引用

如何获取 Class 对象
通过查看 Class 的源码可知,Class 的构造方法是私有的,并且是 JVM 内置的,只能是 JVM 能够创建 Class 对象。
但是,Java 给我们提供了几种获取 Class 对象的方法:
Class 对象获取方法
Class object获取方法示例

运用getClass()

注:每个 Object 的对象都有此函数

String str = "abc";

Class c1 = str.getClass();

运用static method

Class.forName()

(最常被使用)

Class c1 = Class.forName ("java.lang.String");

Class c3 = Class.forName ("java.util.LinkedList$Entry");

Class c4 = Class.forName ("I");

Class c5 = Class.forName ("[I");

运用

.class 语法

Class c1 = String.class;

Class c3 = Main.InnerClass.class;

Class c4 = int.class;

Class c5 = int[].class;

运用

Class.getSuperclass()

注:如果操作对象是ObjectClass.getSuperClass()会返回null

Button b = new Button();

Class c1 = b.getClass();

Class c2 = c1.getSuperclass();

运用

Class c3 = Character.TYPE;

Class c5 = Integer.TYPE;

Class c6 = Long.TYPE;

Class c8 = Double.TYPE;

Class c9 = Void.TYPE;


























这些获取 Class 对象的方法的原理都是获取方法区中字节码的索引
java">class ReflectionDemo
{
	public static void main(String[] args) throws Exception 
	{
		Class clazz = ReflectionDemo.class;
		Class clazz1 = Class.forName("ReflectionDemo");
		Class clazz2 = clazz.getClass();

		System.out.println("Hello World!");
	}
}

上面程序反汇编结果如图:

从第一红框可以看到,javac 把 xxx.class 直接编译为把 xxx 类在方法区中的字码索引返回 Class 类变量,从 Object 和 Class 的源码可以知道 getClass 和 forName 方法都是 JVM 本地方法,所以我认为 Class 类就是 JVM 提供的解析 class 字节码的功能的封装。

Class类的功能函数实例:
java">package cn.itcast.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;

/**
 * @class: ReflectionClassDemo
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-20 上午10:55:13
 * @version: 1.0
 */
public class ReflectionClassDemo {

	public static void main(String args[]) throws Exception {
		ReflectionClassDemo ref = new ReflectionClassDemo();
		ref.getConstructor();

	}

	public void getConstructor() throws Exception {
		Class<?> c = Class.forName("java.lang.Long");
		Class<?> cs[] = { java.lang.String.class };

		System.out.println("\n-------------------------------\n");

		Constructor<?> cst1 = c.getConstructor(cs);
		System.out.println("1、通过参数获取指定Class对象的构造方法:");
		System.out.println(cst1.toString());

		Constructor cst2 = c.getDeclaredConstructor(cs);
		System.out.println("2、通过参数获取指定Class对象所表示的类或接口的构造方法:");
		System.out.println(cst2.toString());

		Constructor cst3 = c.getEnclosingConstructor();
		System.out.println("3、获取本地或匿名类Constructor 对象,它表示基础类的立即封闭构造方法。");
		if (cst3 != null)
			System.out.println(cst3.toString());
		else
			System.out.println("-- 没有获取到任何构造方法!");

		Constructor[] csts = c.getConstructors();
		System.out.println("4、获取指定Class对象的所有构造方法:");
		for (int i = 0; i < csts.length; i++) {
			System.out.println(csts[i].toString());
		}

		System.out.println("\n-------------------------------\n");

		Type types1[] = c.getGenericInterfaces();
		System.out.println("1、返回直接实现的接口:");
		for (int i = 0; i < types1.length; i++) {
			System.out.println(types1[i].toString());
		}

		Type type1 = c.getGenericSuperclass();
		System.out.println("2、返回直接超类:");
		System.out.println(type1.toString());

		Class[] cis = c.getClasses();
		System.out.println("3、返回 Class 中使用的所有的类和所有的接口:");
		for (int i = 0; i < cis.length; i++) {
			System.out.println(cis[i].toString());
		}

		Class cs1[] = c.getInterfaces();
		System.out.println("4、实现的接口");
		for (int i = 0; i < cs1.length; i++) {
			System.out.println(cs1[i].toString());
		}

		System.out.println("\n-------------------------------\n");

		Field fs1[] = c.getFields();
		System.out.println("1、类或接口的所有可访问公共字段:");
		for (int i = 0; i < fs1.length; i++) {
			System.out.println(fs1[i].toString());
		}

		Field f1 = c.getField("MIN_VALUE");
		System.out.println("2、类或接口的指定已声明指定公共成员字段:");
		System.out.println(f1.toString());

		Field fs2[] = c.getDeclaredFields();
		System.out.println("3、类或接口所声明的所有字段:");
		for (int i = 0; i < fs2.length; i++) {
			System.out.println(fs2[i].toString());
		}

		Field f2 = c.getDeclaredField("serialVersionUID");
		System.out.println("4、类或接口的指定已声明指定字段:");
		System.out.println(f2.toString());

		System.out.println("\n-------------------------------\n");

		Method m1[] = c.getMethods();
		System.out.println("1、返回类所有的公共成员方法:");
		System.out.println(m1.length);
		for (int i = 0; i < m1.length; i++) {
			System.out.println(m1[i].toString());
		}
		
		Method m3[] = c.getDeclaredMethods();
		System.out.println("2、返回类自己定义所有的成员方法:");
		System.out.println(m3.length);
		for (int i = 0; i < m3.length; i++) {
			System.out.println(m3[i].toString());
		}

		Method m2 = c.getMethod("longValue", new Class[] {});
		System.out.println("3、返回指定公共成员方法:");
		System.out.println(m2.toString());

	}
}
更多 Class 类和 Class 对象的功能函数请参考 JDK API 手册。

构造方法的反射应用_Constructor 类

java.lang.Object
     java.lang.reflect.AccessibleObject
          java.lang.reflect.Constructor<T>

Constructor 类某个类中的构造方法,一个 Constructor 对象代表某一个类中的一个构造方法,所以通过 Constructor 的对象时可以创建某个类的实例的。

Constructor 类的常用方法:
String getName() 
          以字符串形式返回此构造方法的名称。 
T newInstance(Object... initargs) 
          使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。 
Class<?>[] getParameterTypes() 
          按照声明顺序返回一组 Class 对象,这些对象表示此 Constructor 对象所表示构造方法的形参类型。 
Class<?>[] getExceptionTypes() 
          返回一组表示声明要抛出的异常类型的 Class 对象,这些异常是由此 Constructor 对象表示的底层构造方法抛出的。 
Type[] getGenericExceptionTypes() 
          返回一组 Type 对象,这些对象表示声明要由此 Constructor 对象抛出的异常。 
Class<T> getDeclaringClass() 
          返回 Class 对象,该对象表示声明由此 Constructor 对象表示的构造方法的类。 
更详细的请参考 jdk api 手册

得到某个类所有的构造方法:
例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors()

得到某一个构造方法:
例子: Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
 //获得方法时要用到类型

创建对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));
 //调用 newInstance 的方法时要传递 constructor 所表示的构造方法形式参数相同类型实际参数,否则运行时会报异常

Class.newInstance()方法:
例子:String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到A类默认的构造方法 Constructor 对象,然后用该构造方法的对象创建A类实例对象。该方法内部的具体代码用到了缓存机制来保存默认构造方法的实例对象,免得再次获取构造方法的实例,这也侧面说明反射机制效率比较低。
演示:
java">  //用字节码获取获取 String 的带 StringBuffer 参数的构造方法.返回 Constructor 类型对象
  Constructor constructor = String.class.getConstructor(Class.forName("StringBuffer"));
  
  //再用 Constructor 类中的 newInstance 方法给构造方法实例化.
  String str2=(String)constructor1.newInstance(new StringBuffer("abc"));
  
  //打印返回的字符串角标位置上的字符
  System.out.println(str2.charAt(2));

成员变量的反射_Field 类

java.lang.Object
      java.lang.reflect.AccessibleObject
            java.lang.reflect.Field

Field类代表类中的成员变量,Field 对象代表某个类中的某个成员变量。

Field 类常用的成员方法:
Object get(Object obj) 
          返回指定对象上此 Field 表示的字段的值。 
void set(Object obj, Object value) 
          将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 
String getName() 
          返回此 Field 对象表示的字段的名称。 
boolean getBoolean(Object obj) 
          获取一个静态或实例 boolean 字段的值。 
......
Class<?> getDeclaringClass() 
          返回表示类或接口的 Class 对象,该类或接口声明由此 Field 对象表示的字段。 
Type getGenericType() 
          返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型。 
int getModifiers() 
          以整数形式返回由此 Field 对象表示的字段的 Java 语言修饰符。 
更详细的请参考 jdk api 手册

问题:
得到的 Field 对象是对应到类上面的成员变量,还是对应到对象上的成员变量?Field Method Constructor 都是对类的成员的描述,所以它们的对象都是对类字节码的成员的封装。

演示:
java">  //成员变量的反射
  ReflectPoint pt1 = new ReflectPoint(3, 6);
  //成员变量时共有的可以正常反射
  Field filedY = pt1.getClass().getField("y"); 
  System.out.println(filedY.get(pt1));

  
  //如果成员变量是私有的要强行反射getDeclaredField
  Field fieldX = pt1.getClass().getDeclaredField("x");
  //暴力反射修改字段的访问属性的方法方法 setAccessible(true); 这是继承自 java.lang.reflect.AccessibleObject 的方法
  fieldX.setAccessible(true);
  //获取
  System.out.println(fieldX.get(pt1));

成员变量反射的综合案例
java">/**
 * 需求:演示反射 API 中 Feild 类的用法
 * 
 * 思路: 使用反射替换某个对象中字符字段的值
 * 
 * 步骤:
 * 
 * 总结:
 * Class 对象中的  getFeilds 可以获取该 Class 所有public字段
 * Feild 对象中的 get 方法可以获取某个对象的该字段的值
 * Feild 对象中的 set 方法可以设置某个对象的该字段的值
 * Feild 对象中的 setAccessable 方法可以这种某个对象的该字段的访问属性
 */
package cn.itcast.reflect;

import java.lang.reflect.Field;

/**
 * @class: FieldReflectionDemo
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-20 下午11:34:20
 * @version: 1.0
 */
public class FieldReflectionDemo {

	public String string1 = "ball";
	public String string2 = "basketball";
	public String string3 = "itcast";

	/**
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-20 下午11:34:20
	 * @version: 1.0
	 * @throws ClassNotFoundException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 */
	public static void main(String[] args) throws ClassNotFoundException,
			IllegalArgumentException, IllegalAccessException {
		// TODO Auto-generated method stub
		String value;
		FieldReflectionDemo fieldReflectionDemo = new FieldReflectionDemo();
		Class<?> clazz = Class.forName("cn.itcast.reflect.FieldReflectionDemo");
		Field[] feilds = clazz.getFields();
		for (Field feild : feilds) {
			if (feild.getType() == String.class) {
				value = (String) feild.get(fieldReflectionDemo);
				value = value.replace('b', 'a');
				feild.set(fieldReflectionDemo, value);
			}
		}
		System.out.println(fieldReflectionDemo);
	}

	@Override
	public String toString() {
		return "FieldReflectionDemo [string1=" + string1 + ", string2="
				+ string2 + ", string3=" + string3 + "]";
	}
}

成员方法的反射_Method 类

java.lang.Object
      java.lang.reflect.AccessibleObject
           java.lang.reflect.Method

Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可以是类方法也可以是实例方法(包括抽象方法)。 

Method 类常用成员方法:
Object invoke(Object obj, Object... args) 
          对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。 
 String getName() 
          以 String 形式返回此 Method 对象表示的方法名称。 
 Class<?>[] getParameterTypes() 
          按照声明顺序返回 Class 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型。 
 Class<?> getReturnType() 
          返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型。 

得到类中的某一个方法:
例子: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
 
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式: charAt.invoke(str, 1);
 
如果传递给 Method 对象的 invoke() 方法的第一个参数为 null,说明该 Method 对象对应的是一个静态方法。
 
jdk1.4和jdk1.5的invoke方法的区别:
jdk1.5:public Object invoke(Object obj,Object... args)
jdk1.4:public Object invoke(Object obj,Object[] args),按 jdk1.4的语法,需要将一个数组作为参数传递给 invoke 方法,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用 charAt 方法的代码也可以用 jdk1.4 改写为 charAt.invoke(“str”, new Object[]{1}) 形式。
java">  //获取 String 的字节码对象调用字节码的 getmethod 方法.获取 String 的 charAt 方法.int.class是1.5之后的
  //新特性.可变参数.
  Method methodCharAt = String.class.getMethod("charAt", int.class);
  //调用Method的invoke方法.获取Str1,的第二个角标位置
  System.out.println(methodCharAt.invoke(str1, 2));
使用可变参数这种新特性,有很大的方便,省略了创建数组对象的步骤,但是由于 jdk1.5 保持对 jdk1.4 的向下兼容性,对于带有数组参数的 Method 的 invoke 会有点绕。

对接收数组参数的成员方法进行反射

反射方式执行某个类中的main方法:

目标:
写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调完后,大家要明白为什么要用反射方式去调?

问题:
启动 Java 程序的 main 方法的参数是一个字符串数组,即public static void main(String[] args),通过反射方式来调用这个main方法时,如何为 invoke 方法传递参数,按 jdk1.5的语法,整个数组是一个参数,而按 jdk1.4 的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac 会到底按照哪种语法进行处理jdk1.5肯定要兼容jdk1.4的语法,会按 jdk1.4 的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码ainMethod.invoke(null,new String[]{“xxx”}),javac只把它当作 jdk1.4 的语法进行理解,而不把它当作 jdk1.5 的语法解释,因此会出现参数类型不对的问题。
 
解决办法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了

数组与 Object 的关系及其反射类型

java">/**
 * 需求:演示数组 和 Object 的关系
 * 
 * 思路:
 * 1.获取数组的  Class 对象,比较是否相等
 * 2.打印数组的  Class 对象的名字
 * 3.数组 和 Object 类型之间的类型转换
 * 
 * 步骤:
 * 
 * 总结:
 * 1.java 里面,相同元素类型和相同维度数的数组是同一个类型的数组,对应同一个 Class 对象
 * 2.数组类型的签名是" [ + 元素类型名签名 ",如果是多维数组,也是符合前面的规则,结果就成了几维数组会有几
 * 个" [ "符号
 * 3.数组类型可以向上转型为 Object 类型
 * 4.java 语言中没有多维数组,其实都是一维数组,所谓多维数组,是数组中的元素还是数组,只有最后一层是一个非
 * 数组类型
 */
package cn.itcast.reflect;

/**
 * @class: ArrayAndObject
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-21 上午10:03:02
 * @version: 1.0
 */
public class ArrayAndObject {

	/** 
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-21 上午10:03:02
	 * @version: 1.0
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int [] a1 = new int[4];
		int [] a2 = new int[5];
		int [][] a3 = new int[2][3];
		
		String [] a4 = new String[3];
		
		// 返回 true,说明同类型同维度的数组是同一个 Class 对象
		System.out.println(a1.getClass() == a2.getClass()); 
		// 不可比较,说明同类型不同维度的数组不是同一个 Class 对象
		//System.out.println(a1.getClass() == a3.getClass());
		// 不可比较,说明不同类型同维度的数组不是同一个 Class 对象
		//System.out.println(a1.getClass() == a4.getClass());
		
		// 数组类型的名称是 [ + 类型名签名,如果是多维数组,几维数组用几个 [
		System.out.println(a1.getClass().getName());
		System.out.println(a3.getClass().getName());
		System.out.println(a4.getClass().getName());
		// 数组类型的父类型都是 Object 类型
		System.out.println(a1.getClass().getSuperclass().getName());
		System.out.println(a3.getClass().getSuperclass().getName());
		
		// 数组类型的父类都是 Object 类型,所以数组类型可以上转为 Object 类
		Object aObject1 = a1;
		Object aObject2 = a4;
		
		// 数组中的元素有两种类型,一种是基本类型,一种是引用类型
		//Object[] aObjects3 = a1;
		
		// 数组类型的类型匹配需要匹配两个地方,第一个是否是数组,第二个数组中的元素类型的匹配
		// Object [] aObject4 定义了一个 ,一维数组,其中数组中的元素是 Object 类型
		// a3 是定义了一个一维数组A,数组中的元素是 一维数组B,一维数组B中的元素是 int 类型,一维数组B可以
		// 向上转型为 Object 类型,所以可认为 Java 语言中没有多维数组,其实都是一维数组,所谓多维数组,是
		// 数组中的元素还是数组,只有最后一层是一个非数组类型
		Object[] aObject4 = a3;
		Object[] aObject5 = a4;
		
		
	}

}

数组的反射应用_Array 类

java.lang.Object
      java.lang.reflect.Array

Array 类提供了动态创建和访问 Java 数组的方法。 Array 允许在执行 get 或 set 操作期间进行扩展转换,但如果发生收缩转换,则抛出 IllegalArgumentException。

Array 类都是静态方法,常用成员方法有
static Object newInstance(Class<?> componentType, int length) 
          创建一个具有指定的组件类型和长度的新数组。 
static Object newInstance(Class<?> componentType, int... dimensions) 
          创建一个具有指定的组件类型和维度的新数组。 
static Object get(Object array, int index) 
          返回指定数组对象中索引组件的值。 
static void set(Object array, int index, Object value) 
          将指定数组对象中索引组件的值设置为指定的新值。 
static int getLength(Object array) 
          以 int 形式返回指定数组对象的长度。 

具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。代表数组的 Class 实例对象的 getSuperClass() 方法返回的父类为 Object 类对应的 Class。基本类型的一维数组可以被当作 Object 类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做 Objec t类型使用,又可以当做 Object[] 类型使用。

Arrays.asList()方法处理 int[] 和 String[] 时的差异
java">	int [] a11 = new int[]{1, 2, 3};	
	String [] a12 = new String[]{"a", "b","c"};
	System.out.println(Arrays.asList(a11));
	// 这说明数组中的元素向上转型的时候不会进行自动装箱拆箱
	// 自动装箱拆箱只会在运算符表达式中进行
	//System.out.println(Arrays.asList((Integer [])a11));
	System.out.println(Arrays.asList(a12));
打印结果为:
[[I@4706e02e]
[a, b, c]
这是因为 Arrays 类的 asList 方法在 jdk1.5 和 jdk1.4 中不同,
jdk1.5 :static <T> List<T> asList(T... a) 
jdk1.4:public static List asList(Object[] a)  
jdk1.5 为了兼容 jdk1.5 而首先按照 jdk1.4 的类型运行,所以把 int[] 当做一个 Object 对象,把 String[] 当做一个 Object[] 对象。

Array工具类用于完成对数组的反射操作  

ArrayList_HashSet的比较及Hashcode分析

使用 HashSet 集合元素的时候需要注意,如果已经保存元素已经保存进 HashSet 中,就不要去修改该元素影响 hashCode 值的成员变量,否则可能会造成内存泄露,因为修改完该元素某些影响 hashCode 值的元素后,HashSet contains 方法就不能找到该元素了。但是通过 iterator 遍历该集合可以取到该元素。
java">/**
 * 
 */
package cn.itcast.reflect;

import java.util.HashSet;

/**
 * @class: HashSetModif
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-21 下午12:19:59
 * @version: 1.0
 */
public class HashSetModify {

	/**
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-21 下午12:19:59
	 * @version: 1.0
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		HashSet<Point> points = new HashSet<HashSetModify.Point>();
		Point point1 = new Point(1, 2);
		Point point2 = new Point(2, 4);
		Point point3 = new Point(3, 5);
		points.add(point1);
		points.add(point2);
		points.add(point3);
		
		System.out.println(points);
		point1.x = 16;
		System.out.println(points);
		for (Point point : points) {
			System.out.println(point);
		}
		System.out.println(points.contains(point1));

	}

	static class Point {
		int x;
		int y;

		public Point(int x, int y) {
			super();
			this.x = x;
			this.y = y;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + x;
			result = prime * result + y;
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Point other = (Point) obj;
			if (x != other.x)
				return false;
			if (y != other.y)
				return false;
			return true;
		}

		@Override
		public String toString() {
			return "Point [x=" + x + ", y=" + y + "]";
		}
	}
}
 
更详细的 HashSet 和 ArrayList 用法见  JavaSE 拾遗(8)——JavaSE 集合框架

框架的概念及用反射技术开发框架的原理

什么是框架,例如,我们要写程序扫描.java文件中的注解,要解决哪些问题:读取每一样,在每一个中查找@,找到的@再去查询一个列表,如果@后的内容出现在了列表中,就说明这是一个我能处理和想处理的注解,否则,就说明它不是一个注解或者说至少不是一个我感兴趣和能处理的注解。接着就编写处理这个注解的相关代码。现在sun提供了一个apt框架,它会完成所有前期工作,只需要我们提供能够处理的注解列表,以及处理这些注解的代码。Apt框找到我们感兴趣的注解后通知或调用我们的处理代码去处理。
你做的门调用锁,锁是工具,你做的门被房子调用,房子是框架,房子和锁都是别人提供的。

程序中不处理异常,而是main方法声明抛出异常,便于大家可以集中看主要的关键代码。Class类也提供getResourceAsStream方法的比喻:如果你每次都找我给你商店买可乐,那我还不如直接向你买可乐,即直接提供一个买可乐的方法给你。

框架与框架要解决的核心问题
我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。

框架要解决的核心问题
我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用到你以后写的类(门窗)呢?因为在写才程序时无法知道要被调用的类名,所以,在程序中无法直接new 某个类的实例对象了,而要用反射方式来做。

综合案例
先直接用new  语句创建 ArrayList 和 HashSet 的实例对象,演示用eclipse 自动生成 ReflectPoint 类的 equals 和 hashcode 方法,比较两个集合的运行结果差异。然后改为采用配置文件加反射的方式创建 ArrayList 和 HashSet 的实例对象,比较观察运行结果差异。
java">/**
 * 
 */
package cn.itcast.reflect;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;

/**
 * @class: HashSetModif
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-21 下午12:19:59
 * @version: 1.0
 */
public class ReflectionProperties {

	/**
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-21 下午12:19:59
	 * @version: 1.0
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		InputStream inputStream = new FileInputStream("config.properties");
		Properties properties = new Properties();
		properties.load(inputStream);
		inputStream.close();
		String className = properties.getProperty("className");

		Collection points = (Collection) Class.forName(className)
				.newInstance();
		Point point1 = new Point(1, 2);
		Point point2 = new Point(2, 4);
		Point point3 = new Point(3, 5);
		Point point4 = new Point(3, 5);
		points.add(point1);
		points.add(point2);
		points.add(point3);
		points.add(point4);
		System.out.println(points.size());

	}

	static class Point { 
		//同上一个例子
	}
}

运行结果为:4

用类加载器的方式管理资源和配置文件

java">/**
 * 
 */
package cn.itcast.reflect;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;

/**
 * @class: HashSetModif
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-21 下午12:19:59
 * @version: 1.0
 */
public class ReflectionProperties {

	/**
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-21 下午12:19:59
	 * @version: 1.0
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		// 这个是到运行时用户当前目录下去加载文件
		InputStream inputStream = new FileInputStream("config.properties");
		// 这个是到 classpath 文件目录中去加载文件, 这个只能是读入文件
		inputStream = ReflectionProperties.class.getClassLoader()
				.getResourceAsStream("cn/itcast/reflect/config.properties");
		// Class 对象的 getResourceAsStream 可以使用相对路径
		inputStream = ReflectionProperties.class
				.getResourceAsStream("config.properties");
		// Class 对象的 getResourceAsStream 可以使用其他包的相对路径
		inputStream = ReflectionProperties.class
				.getResourceAsStream("resource/config.properties");
		// Class 对象的 getResourceAsStream 可以使用绝对路径
				inputStream = ReflectionProperties.class
						.getResourceAsStream("/cn/itcast/reflect/config.properties");
		Properties properties = new Properties();
		properties.load(inputStream);
		inputStream.close();
		String className = properties.getProperty("className");

	}
}

由内省到JavaBean

内省 
内省(Introspector)是Java 语言通过反射的原理对  JavaBean 类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过 getName,setName 方法来得到其值或者设置新的值。通过 getName/setName 来访问 name 属性,这就是默认的规则。Java中提供了一套 API 用来访问通过字符串变量传递名字的某个属性的 getter/setter 方法,通过这些 API  对对象属性的操作,减少了代码的数量。这些 API 存放于包java.beans中。

JavaBean
JavaBean 是一个非常简单的遵循某种严格协议的 Java 类,为写成 JavaBean,类必须是具体(非 abstract )的和公共( public )的,并且具有无参数的构造器。JavaBean 严格遵守面向对象的类设计逻辑,不让外部世界访问其任何字段(没有 public 字段)。这样,方法调用是接触 Bean 的唯一途径。每个JavaBean 属性通常都应该遵循简单的方法命名规则,这样应用程序构造器工具和最终用户才能找到 JavaBean 提供的属性,然后查询或修改属性值,对 bean 进行操作。

JavaBean 是一种特殊的 java 类,主要用于传递数据信息,这种 java 类中的方法主要用于访问私有的字段,且这种方法名符合某种命名规则。如果要在两个模块之间传递多个信息,可以将这些信息封装到一个 JavaBean 中,这种 JavaBean 的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,这就是 getter 和 setter 方法,JavaBean 的属性是根据其中的 setter 和 getter 方法来确定的,而不是根据其中的成员变量。如果方法名为 setId,中文意思即为设置 id,至于你把它存到哪个变量上,不用管,如果方法名为 getId,中文意思即为获取 id,至于你从哪个变量上取,不用管,去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。我们在使用 javabean 的时候,就是通过这个属性名使用 reflection method 来获取 getter setter 方法,再通过 getter setter 方法来操作 javabean 对象的属性。

-->setId()的属性名是id
-->getLast()的属性名是last
-->setCPU的属性名是CPU
-->getUPS的属性名是UPS

总之:
一个类被当作 javaBean 使用时,JavaBean 的属性是根据方法名推断出来的,它根本看不到 java 类内部的成员变量。
 
一个符合 JavaBean 特点的类可以当作普通类一样进行使用,也可以当 JavaBean 使用,把它当 JavaBean 用好处如下:
1.在 Java EE 开发中,经常要使用到 JavaBean。 很多环境就要求按 JavaBean 方式进行操作。
2.JDK 中提供了对 JavaBean 进行操作的一些 API,这套 API 就称为内省。如果在写程序的时候,你只知道要访问的属性名x保存在某个字符串变量 xstring 中,要通过 getX 方法来访问私有的 x,需要自己根据属性名来组合为 getter setter 方法名,然后再使用反射来访问这些方法,比较麻烦,所以JDK 提供了内省这套 API 操作JavaBean 比用普通类的方式更方便。
比如:
java">/**
 * 需求:自己模拟内省的操作
 */
package cn.itcast.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @class: ReflectionCopyObject
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-20 下午1:33:47
 * @version: 1.0
 */
public class ReflectionCopyObject {

	public Object copy(Object object) throws Exception {
		// 获得对象的类型
		Class<?> classType = object.getClass();
		System.out.println("Class:" + classType.getName());

		// 通过默认构造方法创建一个新的对象
		Object objectCopy = classType.getConstructor(new Class[] {})
				.newInstance(new Object[] {});

		// 获得对象的所有属性
		Field fields[] = classType.getDeclaredFields();

		for (int i = 0; i < fields.length; i++) {
			Field field = fields[i];

			String fieldName = field.getName();
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			// 获得和属性对应的getXXX()方法的名字
			String getMethodName = "get" + firstLetter + fieldName.substring(1);
			// 获得和属性对应的setXXX()方法的名字
			String setMethodName = "set" + firstLetter + fieldName.substring(1);

			// 获得和属性对应的getXXX()方法
			Method getMethod = classType.getMethod(getMethodName,
					new Class[] {});
			// 获得和属性对应的setXXX()方法
			Method setMethod = classType.getMethod(setMethodName,
					new Class[] { field.getType() });

			// 调用原对象的getXXX()方法
			Object value = getMethod.invoke(object, new Object[] {});
			System.out.println(fieldName + ":" + value);
			field.setAccessible(true);
			System.out.println(field.get(object).getClass());
			// 调用拷贝对象的setXXX()方法
			setMethod.invoke(objectCopy, new Object[] { value });
		}
		return objectCopy;
		
	}

	/**
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-20 下午1:33:47
	 * @version: 1.0
	 * @throws Exception 
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		Customer customer = new Customer("Tom", 21);
		customer.setId(new Long(1));

		Customer customerCopy = (Customer) new ReflectionCopyObject().copy(customer);
		System.out.println("Copy information:" + customerCopy.getId() + " "
				+ customerCopy.getName() + " " + customerCopy.getAge());
	}

}

class Customer {
	private Long id;

	private String name;

	private int age;

	public Customer() {
	}

	public Customer(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

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

	public int getAge() {
		return age;
	}

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

对 JavaBean 的内省操作

内省访问JavaBean有两种方法:
一、通过属性描述符 PropertyDescriptor 来操作 Bean 对象
二、通过Introspector类获得Bean对象的 BeanInfo,然后通过 BeanInfo 来获取所以属性的描述器( PropertyDescriptor ),通过某个属性描述器就可以获取这个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法。

PropertyDescriptor

java.lang.Object
      java.beans.FeatureDescriptor
             java.beans.PropertyDescriptor

PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性

构造器

PropertyDescriptor(String propertyName, Class<?> beanClass) 
          通过调用 getFoo 和 setFoo 存取方法,为符合标准 Java 约定的属性构造一个 PropertyDescriptor。

常用方法

Method getReadMethod() 

          获得应该用于读取属性值的方法。 
 Method getWriteMethod() 
          获得应该用于写入属性值的方法。 

Class<?> getPropertyType() 
          获得属性的 Class 对象。 

Introspector 类

Introspector 类为通过工具学习有关受目标 Java Bean 支持的属性、事件和方法的知识提供了一个标准方法。 

java.lang.Object

       java.beans.Introspector

常用方法

static BeanInfo getBeanInfo(Class<?> beanClass) 
          在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件。 


BeanInfo  接口
PropertyDescriptor[] getPropertyDescriptors() 
          获得 beans PropertyDescriptor。 
java">/**
 * 需求:使用 PropertyDescriptor 进行内省操作
 * 
 * 思路:
 * 
 * 步骤:
 * 
 * 总结:
 * 1.没有 PropertyDescriptor ,我们需要自己根据属性名字符串,解析为 getter、setter 名字符串,再用 Class 对
 * 象的 getMethod 方法获取对应的 getter、setter 方法对象
 * 2.有 PropertyDescriptor 之后,我们只需要传递一个属性名 字符串 + Class对象,就可直接使用 getReadMethod 
 * 获取到 getter 方法对象
 */
package cn.itcast.reflect;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

/**
 * @class: IntrospectorDemo
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-22 上午9:15:36
 * @version: 1.0
 */
public class IntrospectorDemo {

	/**
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-22 上午9:15:36
	 * @version: 1.0
	 */
	public static void main(String[] args) throws Exception {
		Point point = new Point(2, 5);
		String proName = "x";

		System.out.println(getProperty1(point, proName));
		setProperty(point, proName, 8);
		System.out.println(getProperty2(point, proName));
	}

	private static void setProperty(Point point, String proName, int value)
			throws Exception {
		PropertyDescriptor proDescriptor = new PropertyDescriptor(proName,
				Point.class);
		Method methodSetX = proDescriptor.getWriteMethod();
		methodSetX.invoke(point, value);
	}

	private static int getProperty1(Point point, String proName)
			throws Exception {
		PropertyDescriptor proDescriptor = new PropertyDescriptor(proName,
				Point.class);
		Method methodGetX = proDescriptor.getReadMethod();
		Object objx = methodGetX.invoke(point);
		return Integer.parseInt(objx.toString());
	}

	private static int getProperty2(Point point, String proName)
			throws Exception {
		BeanInfo beanInfo = Introspector.getBeanInfo(point.getClass());
		PropertyDescriptor[] proDescriptors = beanInfo.getPropertyDescriptors();
		for (PropertyDescriptor prop : proDescriptors) {
			if (prop.getName().equals(proName)) {
				Method methodGetx = prop.getReadMethod();
				Object objx = methodGetx.invoke(point);
				return Integer.parseInt(objx.toString());
			}
		}
		return 0;
	}

}

class Point {
	private Integer x;
	private Integer y;

	public Point() {

	}

	public Point(Integer x, Integer y) {
		super();
		this.x = x;
		this.y = y;
	}

	public Integer getX() {
		return x;
	}

	public void setX(Integer x) {
		this.x = x;
	}

	public Integer getY() {
		return y;
	}

	public void setY(Integer y) {
		this.y = y;
	}
}

使用BeanUtils工具包操作JavaBean

使用 Apache 的 BeanUtils 工具包来完成对 JavaBean 的操作

使用 BeanUtils 工具包之前先需要在 project 里添加 jar 包,添加 jar 包有两种方式:
1.只是添加到 buildingpath 中,这个在本地运行,但是在其他机器上如果没有这个 jar 就不能运行,因为生成的 bin 目录下没有该 jar
2.把 jar 添加到项目中,再添加到 buildingpath 中,这个是在 building 的时候,把该 jar 一起 building 到 bin 目录中

第一种方式:在 Project properties 中的 buildingpath 下配置, Add JARs 是添加同一个 WorkSpace 中的 jar,比如其他 project 生成的 jar,Add External JARs 是添加文件系统中任意位置的 jar,这个地方只是把 jar 的路径添加到相应的配置文件中了,如果在文件系统中把对应的 jar 删掉,编译和运行时也会找不到需要的 class。

第二种方式:直接把 jar 复制到 project 中,比如在 project 中建一个 lib 目录专门用来保存 jar,然后再把该 jar 添加到 project 的 buildingpath,在 building 的时候就能把该 jar 一并添加进构建后的 jar 文件。


用 eclipse 给项目添加 jar 包,如果先导入 Apache 的 beanutils 包,会发现由于 beanutils 包依赖于logging 包,所以还需要导入 logging 包。

在前面内省例子的基础上,使用 Apache 的 BeanUtils 工具包来完成对 JavaBean 的操作
BeanUtils
java.lang.Object
     org.apache.commons.beanutils.BeanUtils

Utility methods for populating JavaBeans properties via reflection.

static String getProperty(Object bean, String name) 
static void setProperty(Object bean, String name, Object value) 
static void copyProperties(Object dest, Object orig) 
static Map describe(Object bean)   把 javabean 的所有属性以 map 返回,和 json 串相似 {name:"xxx",  age:'17'}
static void populate(Object bean, Map properties)  把一个 map 填充到 javabean 对象中


从上面我们可以看到 Point 的 x  是 int  但是我们用 Beanutils 设置值的时候是用 Object  类型(通常是 String 类型)设置进去的,用 Beanutils 去取值的时候返回是 String 类型的。这是因为 web 前端通常使用的 String 类型的数据,和用户交互输入的也是 String 类型的数据,所以 Beanutils 直接支持 String 类型数据,免去了 String 到 基本类型数据的解析,和基本类型数据到 String 的转换。
java">/**
 * 
 */
package cn.itcast.reflect;

import org.apache.commons.beanutils.BeanUtils;

/**
 * @class: IntrospectorDemo
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-22 上午9:15:36
 * @version: 1.0
 */
public class IntrospectorDemo {

	/**
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-22 上午9:15:36
	 * @version: 1.0
	 */
	public static void main(String[] args) throws Exception {

		Point point = new Point(2, 5);
		String propertieName = "x";
		BeanUtils.setProperty(point, propertieName, "8");
		System.out.println(point.getX());
		System.out.println(BeanUtils.getProperty(point, propertieName));
		System.out.println(BeanUtils.getProperty(point, propertieName).getClass()
				.getName());

		BeanUtils.setProperty(point, propertieName, 8);
		System.out.println(BeanUtils.getProperty(point, propertieName).getClass()
				.getName());
		// 我们看到虽然属性x的类型是Integer,但是我们设置的时候无论是Integer还是String,BeanUtils的内部
		// 都是当成String来处理的。
	}
	
	public static class Point {
		private int x;
		private int y;

		public Point() {

		}

		public Point(Integer x, Integer y) {
			super();
			this.x = x;
			this.y = y;
		}

		public Integer getX() {
			return x;
		}

		public void setX(Integer x) {
			this.x = x;
		}

		public Integer getY() {
			return y;
		}

		public void setY(Integer y) {
			this.y = y;
		}
	}
}
BeanUtils 操作的类必须是 public 修饰过的,所以这里吧 Point 设置 pulic  static 了,把 JavaBean 放在某个类的里面,这种在正式使用的时候,估计不会有这种设计,因为 JavaBean 本来就是公开的,用来传递数据的类。

BeanUtils支持javabean属性的级联操作
java">/**
 * 需求:演示 BeanUtils 支持 javabean 属性的级联操作
 */
package cn.itcast.reflect;

import java.util.Date;

import org.apache.commons.beanutils.BeanUtils;

/**
 * @class: BeanUtilsDemo
 * @package: cn.itcast.reflect
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-22 下午1:20:10
 * @version: 1.0
 */
public class BeanUtilsDemo {

	/**
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-22 下午1:20:10
	 * @version: 1.0
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		Person person = new Person();
		String propertyName = "birthday.time";
		System.out.println(BeanUtils.getProperty(person, propertyName));
	}

	public static class Person {
		private Date birthday;

		public Person() {
			birthday = new Date();
		}

		public Date getBirthday() {
			return birthday;
		}

		public void setBirthday(Date birthday) {
			this.birthday = birthday;
		}
	}
}

Java7的新特性
Map map = (name:"xxx",age:"18");   // Map可以这样定义, 这和 json 有点像

PropertiesUtils类
java.lang.Object
      org.apache.commons.beanutils.PropertyUtils

Utility methods for using Java Reflection APIs to facilitate generic property getter and setter operations on Java objects.
static Object getProperty(Object bean, String name) 
static void setProperty(Object bean, String name, Object value) 

BeanUtils是以字符串的形式对javabean进行操作,
而PropertiesUtils是以属性本身的类型进行操作。
这是两者的区别。
实例:
java">       //eanUtils工具包 和logging包实现对JavaBean的操作

       //利用Beanutils工具包可以对嵌套的JavaBean类中的属性进行操作

       BeanUtils.setProperty(jbc, "brithday.time", 111);

       System.out.println(BeanUtils.getProperty(jbc, "brithday.time"));

       

       //PropertyUtils工具类传入的参数和拿出的参数必须和属性本身的类型一致

       PropertyUtils.setProperty(jbc, "brithday.time", 123);

       System.out.println(PropertyUtils.getProperty(jbc, "brithday.time"));

       

       //利用BeanUtils工具实现JavaBean与Map的转换

       Map map = BeanUtils.describe(jbc);

       System.out.println(map);

       BeanUtils.setProperty(map, "name", "xx");

       System.out.println(map);

Web 开发框架 Struts 中的 FormBean 就是通过内省机制来将表单中的数据映射到类的属性上,因此要求 FormBean 的每个属性要有 getter/setter 方法。但也并不总是这样,什么意思呢?就是说对一个 Bean 类来讲,我可以没有属性,但是只要有 getter/setter 方法中的其中一个,那么 Java 的内省机制就会认为存在一个属性,比如类中有方法 setMobile ,那么就认为存在一个 mobile 的属性。


将 Java 的反射以及内省应用到程序设计中去可以大大的提供程序的智能化和可扩展性。有很多项目都是采取这两种技术来实现其核心功能,例如我们前面提到的 Struts ,还有用于处理 XML 文件的 Digester 项目,其实应该说几乎所有的项目都或多或少的采用这两种技术。在实际应用过程中二者要相互结合方能发挥真正的智能化以及高度可扩展性。


http://www.niftyadmin.cn/n/1870006.html

相关文章

JVM 指令集总结

1.凡是带const的表示将什么数据压操作数栈。 如&#xff1a;iconst_2 将int型数据2压入到操作数栈 aconst_null 将null值压入栈。 2.bipush和sipush 表示将单字节或者短整形的常量值压入操作数栈。 3.带ldc的表示将什么类型数据从常量池中压入到操作数栈。 如&#xff1a;ldc…

JavaSE 拾遗(17)——JavaSE 高新技术基础增强...注解

注解的了解和入门 注解是 jdk1.5 的新特性 什么是注解 注解就相当于标签&#xff0c;给什么什么加上注解就相当于给什么什么贴上标签&#xff0c;这个标签在 编译、加载、JVM 执行的某个阶段可以读出来使用&#xff0c;判断加标签元素的具有某方面的属性。因为标签这种东西仍…

dataTable 参数详解

//translator codepiano //blog codepiano //email codepiano.ligmail.com //尝试着翻译了一下&#xff0c;难免有错误的地方&#xff0c;欢迎发邮件告知&#xff0c;多谢。 /*------------------------------------------------Feature-------------------------------------…

JavaSE 拾遗(18)——JavaSE 高新技术基础增强...类加载器和动态代理

类加载器 类加载器及其委托机制的深入分析 什么是类加载器 类加载就是在需要的时候把 class 字节码文件从硬盘加载到内存中 JVM 的方法区中&#xff0c;并完成 Verifying、Preparing、Resolving、Initialing&#xff0c;把字节码数据转换为 Class 对象的功能模块。 框图中各个…

bootstrap+jQuery.validate表单校验

谈谈表单校验 这大概是一种惯例&#xff0c;学习前台后台最开始接触的业务都是用户注册和登录。现在社会坚持以人为本的理念&#xff0c;在网站开发过程同样如此。User是我们面对较多的对象&#xff0c;也是较核心的对象。最开始的用户注册和登陆这块&#xff0c;也就尤为重要…

JavaSE 拾遗(19)——交通灯管理系统

1、项目需求 模拟实现十字路口的交通灯管理系统逻辑&#xff0c;具体需求如下&#xff1a; 异步随机生成按照各个路线行驶的车辆。 例如&#xff1a; 由南向而来去往北向的车辆 ---- 直行车辆 由西向而来去往南向的车辆 ---- 右转车辆 由东向而来去往南向的车辆 ---- 左转车辆…

constraint的一些用法总结

主要就是增加约束的 以下几种约束 、并 一一列举&#xff1a; 1.主键约束&#xff1a; 要对一个列加主键约束的话&#xff0c;这列就必须要满足的条件就是分空 因为主键约束&#xff1a;就是对一个列进行了约束&#xff0c;约束为&#xff08;非空、不重复&#xff09; 以下是…

JavaSE 拾遗(20)——银行调度系统

Main.java /*** 需求&#xff1a;银行业务调度系统* 模拟实现银行业务调度系统逻辑&#xff0c;具体需求如下&#xff1a;* 1.银行内有6个业务窗口&#xff0c;1 - 4号窗口为普通窗口&#xff0c;5号窗口为快速窗口&#xff0c;6号窗口为VIP窗口。* 2.有三种对应类型的客户&…