黑马程序员---Java基础加强---反射

-------  android培训 java培训 、期待与您交流! ----------

反射

一、Class类

1.定义
java程序中的各个java类也属于同一类事物,而描述这类事物的Java类就是Class。(此Class类中可以描述java中所

有类的属性,如,他们都有类名、都有方法、都有属性、都有所继承的类、所实现的接口、都有所属的包等等,这些

都是他们共有的属性,所以可以用一个类来统一进行描述)。

2.Class对象

Class的每一个实例对象,代表一份字节码即类在内存中的二进制表示。


3.与class的区别

Class是一个类名,描述一类事物;而class是一个类文件的后缀名,表示文件的类型,表示是一个类文件

4.创建Class实例对象的三种方法
以类Date为例
(1)类名.class

Class c=Date.class;

(2)对象.getClass();

Class c2=new Date().getClass();

(3)Class.forName("类名")

Class c3=Class.forName("java.util.Data");

此方法得到的字节码可以分为两种情况:

第一,当此字节码在内存中时,则直接返回此字节码即可;

第二,当此字节码不在内存中时,则用类加载器先将此字节码加载进内存,缓存在jvm中,然后再返回此字节码。

存在jvm中,这样以后再用到此字节码的时候就不用再加载了,直接用即可。

5.9种基本数据类型的字节码
boolean->boolean.class, byte->byte.class, char->char.class, short->short.class, int->int.class,

long->long.class,  float->float.class,  double->double.class,  void->void.class 

这9种基本数据类型的字节码也都是Class类的实例对象。

6.Class类中的常用方法

例子:

public class ReflectTest 
{
	public static void main(String[] args) throws Exception
	{
		// TODO Auto-generated method stub
		String s1=new String();
		Class c1=String.class;
		Class c2=s1.getClass();
		Class c3=Class.forName("java.lang.String");
		System.out.println(c2);//打印结果为class java.lang.String
		System.out.println(c1==c2);//结果为true
		System.out.println(c1==c3);//结果为true
		//以下是方法的使用
		//1、Class.isPrimitive()返回此字节码是不是基本数据类型的字节码
		System.out.println(c1.isPrimitive());//结果为false                    
		System.out.println(int.class.isPrimitive());//结果为true
		//2、返回此字节码是否是数组类型的字节码
		System.out.println(int[].class.isArray());//结果为true
		//3、判断
		System.out.println(int.class==Integer.class);//结果为false
		//每个基本数据类型的字节码都与它对应的引用数据类型.TYPE相等
		System.out.println(int.class==Integer.TYPE);//结果为true
	}
}
总之,在源程序中出现的类型,都有各自的Class实例对象,例如:int[],void,int

二、反射

1.概念

反射就是将java类中的各个成分映射成相应的java类。

类中的变量,方法,构造函数,包等等信息,就是用相应类的实例对象来表示的,他们是Constructor、Field、

Method、Package等等,Method的每一个实例对象,就代表一个类中具体的方法。

2.构造方法的反射应用
(1)构造方法对应的类为Constructor

(2)得到类中所有的构造方法,利用方法getConstructors()

Constructor[] constructors=String.class.getConstructors();得到类中的某一个构造方法,利用方法getConstructor(对应的构造方法需要的参数类型的字节码)

Constructor constructor=String.class.getConstructor(对应的构造方法需要的参数类型的字节码);

(3)通过反射来创建对象的过程如下:

1> 得到类的字节码

2> 利用类的字节码调用方法getConstructor(构造方法需要的参数类型的字节码)来得到具体的要用到的构造方

法,即得到Constructor的实例对象

3> 通过得到的Constructor的实例对象再调用方法newInstance(创建对象时要传入的参数),来创建此类的对象。

即为:Class -> Constructor->创建对象

注意上面两处传入的参数类型是一致的。

例子:

import java.lang.reflect.Constructor;
/**
 *需求:利用反射创建一个对象String s=new String(new StringBuffer("abc"));
 * */
public class ConstructorTest 
{
	public static void main(String[] args)throws Exception 
	{
		// TODO Auto-generated method stub
		//第一步:得到类的字节码
		Class cs=String.class;
		/*第二步:通过字节码得到想要的构造方法;
		注意此步骤中,必须写入构造方法中所要传入的变量类型的字节码*/
		Constructor constructor=cs.getConstructor(StringBuffer.class);
		/*第三步:得到相应的构造方法之后,创建想要的类的对象;
		    注意此步骤中,必须写上(String)类型转换,因为编译器并不知道
		    你所创建的对象的类型,它只是检查语法是否正确;
		  调用newInstance方法时必须传入变量的具体值*/
		String s=(String)constructor.newInstance(new StringBuffer("abc"));
		//建立好了String类型的对象之后,则可以使用对象所有的方法。
		System.out.println(s.charAt(2));//结果为c
	}
}

(4)Class.newInstance()

Class.newInstance()为无参的构造方法,此方法即为Class->创建对象.比以上方法减少一步

若需求为:利用反射实现String s=new String();

则可以写成:String s=String.class.newInstance();

实现原理:

该方法内部先得到默认的构造方法,然后利用该构造方法创建实例对象

该方法内部用到了缓存机制来保存默认构造方法的实例对象,这样以后可以直接使用了。

3.成员变量的反射

(1)成员变量对应的类为Field类。此类的对象,代表某一个类中的一个成员变量即某一个类中的某一个字段

(2)通过反射得到某一个类得对象中的某一个字段的值

步骤如下:即为:类对象->Class->Field->get(对象)(即得到此对象上次字段的值)

对于字段是公有的:

1> 得到类的字节码

2> 通过方法getField(字段的字符串形式)得到类中的某个字段

3> 通过得到的字段来调用方法get(对象)来得到此类的某一个对象的此字段的值。

对于字段是私有的:

1> 得到类的字节码

2> 通过方法getDeclaredField(字段的字符串形式)来得到类中的私有的字段(即此字段可以被看见了)

注意,不管是私有的还是公有的字段,此方法都适用。

3> 通过调用方法setAccessible(true)来实现能够拿到此变量的值。

4> 通过得到的字段来调用方法get(对象)来得到此类的某一个对象的此字段的值。

以上这种方法为暴力反射。

(3)暴力反射 
暴力反射就是将某个类私有字段的访问检查去掉

例如Person类中有一个私有的age字段,如果要反射出这个字段,则需要调用getDeclaredField(),

如果使用getField则会抛NOSuchFieldException未找到字段异常,

如果调用该字段的get或者set方法会抛IllegalAccessException非法的访问异常,

我们可以通过该字段的setAccessible(true)方法来告诉编译器是否进行访问检查.true就代表不进行访问检查.

例子:

import java.lang.reflect.Field;
public class FieldTest 
{
	public static void main(String[] args)throws Exception
	{
		//FieldCode fc=new FieldCode(3,4);
		//通过反射来创建类的对象
		FieldCode fc=FieldCode.class.getConstructor(int.class,int.class).newInstance(4,5);
		
		//得到此类的字节码
		Class c=fc.getClass();
		//通过字节码来调用函数getField(String name)方法来得到类的某个字段
		Field fieldY=c.getField("y");
		//通过调用方法get(对象)来得到此对象对应的此字段的值
		System.out.println(fieldY.get(fc));
		
		//通过调用方法getDeclaredField(String name)来得到私有成员变量的字段
		Field fieldX=c.getDeclaredField("x");
		//通过方法setAccessible(true)来使此私有字段可访问
		fieldX.setAccessible(true);
		//通过调用方法get(对象)来取得对应的值
		System.out.println(fieldX.get(fc));				
	}
}
class FieldCode
{
	private int x;
	public int y;
	public FieldCode(int x, int y) 
	{
		super();
		this.x = x;
		this.y = y;
	}	
}

(4)成员变量反射的综合案例

需求:利用反射将一个类中所有的字符串字段中的b改为a。

步骤:

1> 得到一个想要进行操作的对象。

2> 得到此对象的所有的字段,利用方法getFields()

3> 遍历这些字段,并判断这些字段哪些属于字符串

4> 利用方法replace(old,new)来完成替换功能。

注意要想通过反射来得到字段,则必须明确是要操作哪个对象,因为不同的对象其字段的值也不同。
例子:

import java.lang.reflect.Field;
public class FieldTest 
{
	public static void main(String[] args)throws Exception
	{
		//将类FieldCode中的所有字符串字段中的b替换成a
		//1、得到此类的对象
		FieldCode f=FieldCode.class.getConstructor(int.class,int.class).
				             newInstance(5,6);
		//2、的到此类中的所有的字段
		Field[] fields=f.getClass().getFields();
		//3、遍历此类的所有字段
		for (Field field : fields) 
		{
			if (field.getType()==String.class) 
			{
				//4.得到此字段的值
				String oldStr=(String)field.get(f);
				//5.替换
				String newStr=oldStr.replace('b', 'a');
				//6、将替换后的值给此对象,让此对象知道
				field.set(f, newStr);	
			}	
		}
		System.out.println(f);	
	}
}
class FieldCode
{
	private int x;
	public int y;
	public String str1="abcde";
	public String str2="basketball";
	public String str3="itcast";
	public FieldCode(int x, int y) 
	{
		super();
		this.x = x;
		this.y = y;
	}	
	public String toString()
	{
		return str1+","+str2+","+str3;
	}
}

4.成员方法的反射

(1)成员方法对应的类为Method,此类对象是为类中的对象而不是具体对象的方法。

(2)需求:利用反射来达到str.charAt(1)的效果

步骤:

1> 通过调用字节码中的方法getMethod(方法名字符串,此方法的参数类型的字节码)来获取类中对应的方法。方

法的参数类型字节码主要是用来区分重载函数的。

2> 通过方法invoke(对象,参数值)来决定此方法作用的对象。

例子:

import java.lang.reflect.Method;
public class MethodTest 
{
	public static void main(String[] args)throws Exception 
	{
		// TODO Auto-generated method stub
		//String str=new String("abcd");或者使用以下方式来获取对象
		String str=String.class.getConstructor(StringBuffer.class).
				newInstance(new StringBuffer("abcd"));
		
		//1、得到类中相应的方法
		Method method1=str.getClass().getMethod("charAt", int.class);
		//2、调用方法对象的方法invoke(对象,参数值)来决定此方法要作用在哪个对象上
		//以及传入方法中的参数值
		System.out.println(method1.invoke(str, 1));
	}
}

(3)jdk1.4和jdk1.5中invoke()方法的区别

主要区别为参数列表的形式不同

jdk1.4中invoke()方法的参数形式用的是数组型的

格式:public Object invoke(Object obj,Object[] args)//obj为此成员方法要作用什么对象身上,

//数组即为方法的参数列表值,

如写成:method1.invoke(str,new Object{1});

jdk1.5中invoke()方法的参数列表运用的是可变参数

格式:public Object invoke(Object obj,Object...args)

注意:

1> invoke方法是方法对象的方法,即是方法Method类的对象method1上的对象。

2> invoke(null,参数值)表示此成员方法是静态的,不用通过对象调用。

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

需求:写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法

分析:要想达到根据用户提供的类名来执行该类中的main方法,则即为在运行环境中用户来输入想要运行的类,则此

类就传入到了主类的main函数的参数数组中,即以字符串的形式存在了,而调用此类的main函数,要么通过类名调用

,要么通过此类的对象调用,但由于此类已经被封装成了字符串,所以这两种都是没办法用的,所以用反射的形式来

完成调用此类的main函数,

步骤为:

得到此类的字节码Class->得到相应的main方法Method->main方法作用于什么对象,

并指定传入main方法的参数即调用invoke()。

注意:

用户传入的类名是在运行环境中的参数列表中传入即写入:cn.itcast.day1.StartClassName
则此类就传入到了MethodTest类中的main方法参数中。
 例子:

import java.lang.reflect.Method;
public class MethodTest 
{
	public static void main(String[] args)throws Exception 
	{
		// TODO Auto-generated method stub
		//String str=new String("abcd");或者使用以下方式来获取对象
		String str=String.class.getConstructor(StringBuffer.class).
				newInstance(new StringBuffer("abcd"));
		//得到类中相应的方法
		Method method1=str.getClass().getMethod("charAt", int.class);
		//调用方法对象的方法invoke(对象,参数值)来决定此方法要作用在哪个对象上
		//以及传入方法中的参数值
		System.out.println(method1.invoke(str, 1));
		System.out.println("--------------main数组测试------------------");
		//1、得到用户传来的类名的字符串形式
		String startclassname=args[0];
		//2、通过反射得到此类的main方法
		Method method=Class.forName(startclassname).getMethod("main",String[].class);
		//3、将此方法作用此什么对象上,并传入什么样的参数(即调用此方法,并传入参数)
		method.invoke(null,(Object)new String[]{"123","456","789"});
		//注意,由于main方法中的参数是一个字符串数组型的,那么该如何为
		//invoke方法传递参数?若传入的参数为new String[]{"123","456","789"}),则java会
		//将它进行拆包,当成三个参数传入main方法的一个参数中,而不是单独的一个数组,所
		//以会出现:IllegalArgumentException: wrong number of arguments的异常现象,
		//所以解决的办法有两种:第一是:method.invoke(null,(Object)new String[]{"123","456","789"});
		//即告诉编译器,我的这个数组是一个整体,你不要再把我拆包,拆成三个了
		//第二是method.invoke(null,new Object[]{new String[]{"123","456","789"}});
		//即表示,你不是要拆包吗,我再包装一层数组,你拆吧,拆开之后是一个数组整体。
	}
}
class StartClassName
{
	public static void main(String[] args)
	{
		for (String string : args) 
		{
			System.out.println(string);		
		}	
	}
}

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

(1)对于数组:具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。

(2)代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。

(3)基本类型的一维数组可以被当做Object类型使用,但不能当做Object[]类型使用。而非基本类型的一维数组既

可以被当做Object类型使用也可以当做Object[]类型使用。

(4)将数组直接打印出来而不是再写for循环,

即利用的是方法public static List asList(Object obj),即返回的是List集合,

或者方法Arrays.toString(i);

对于System.out.println(Arrays.asList(s1));//[a, b, c]

System.out.println(Arrays.asList(i));//[[I@12452e8]

利用方法public static List asList(Object obj),返回的是List集合

而List集合中存放的是对象,对于数组S1它里面的对象为String,而String是一个

引用数据类型的,所以直接将此数组中的每个元素分别存入集合中;而i数组中的元素

类型为int型的,是基本数据类型,不是引用数据类型,所以它里面的元素不能直接被当做

对象来存入集合中,所以把整个数组当做了一个整体,作为一个对象存入到了集合中。

(5)即总结:public static List asList(Object obj)方法使用的是数据类型是引用数据类型

Arrays.toString(i);方法使用于打印数据类型为任何数据类型的数组中的元素。

例子:

import java.util.Arrays;
public class ReflectArrayTest 
{
	public static void main(String[] args) 
	{
		// TODO Auto-generated method stub
		int[] a1=new int[2];
		int[] a2=new int[3];
		int[][] a3=new int[2][3];
		String[] a4=new String[2];
		System.out.println(a1.getClass()==a2.getClass());//结果为true
		//System.out.println(a1.getClass()==a3.getClass());//结果为false
		//System.out.println(a1.getClass()==a4.getClass());//结果为false
		//得到数组a1的字节码
		System.out.println(a1.getClass());//结果为class [I
		//得到字节码的名字
		System.out.println(a1.getClass().getName());//结果为[I
		System.out.println("-------第二部分------------------------");
		//结果都为:java.lang.Object
		System.out.println(a1.getClass().getSuperclass().getName());
		System.out.println(a4.getClass().getSuperclass().getName());
		System.out.println("----------第三部分---------------------");
		//3、注意有下面的等式
		Object obj1=a1;//此式是成立的
		//Object[] obj2=a2//此式是不成立的
		Object obj3=a3;//此式是成立的
		Object obj4=a4;//此式是成立的
		Object[] obj5=a4;//此式是成立的
		Object[] obj6=a3;//此式是成立的	
		System.out.println("-------------第四部分------------------");
		//4、要想直接打印出数组中的元素,则以下方法
		String[] s1=new String[]{"a","b","c"};
		int[] i=new int[]{1,2,3};
		System.out.println(Arrays.asList(s1));//[a, b, c]
		System.out.println(Arrays.asList(i));//[[I@12452e8]
		System.out.println(Arrays.toString(i));//[1,2,3]
		System.out.println(Arrays.toString(s1));//[a,b,c]
	}
}
(6) 数组的反射应用
对数组进行反射的类为Array,主要方法有:Array.getLength(数组名字)

Array.get(数组名称,角标)(即得到数组中某个角标的元素)

例子:

import java.lang.reflect.Array;
import java.util.Arrays;
public class ReflectArrayTest 
{
	public static void main(String[] args) 
	{
		int[] i=new int[]{1,2,3};
		System.out.println("-------------第五部分-对数组进行反射操作的类Array------------------");
		printTest("xyz");
		printTest(i);	
	}
	//即对于对象,看是否是数组,是,则拆包并打印每个数组元素;不是,则直接打印此对象。
	private static void printTest(Object obj) 
	{
		// TODO Auto-generated method stub
		//1.得到此对象的字节码
		Class clazz=obj.getClass();
		if (clazz.isArray()) 
		{
			//得到此数组的长度
			int len=Array.getLength(obj);
			for (int y = 0; y < len; y++) 
			{
				System.out.println(Array.get(obj, y));		
			}		
		} 
		else 
		{
			System.out.println(obj);
		}	
	}
}

三、ArrayList_HashSet的比较及Hashcode分析

1.ArryaList集合特点:此集合中的元素是有序的,即先进来的元素就放在集合前面,后进来的元素就放在后面;元

素可重复。

2.HashSet集合特点:集合中的元素是无序的,并且是不可重复的。通过实现方法hashcode和方法equals来达到元素

唯一的目的。
3.hashCode方法的作用:

第一:它使用于运用hash值的结构中;

第二:它将集合分成了几个区域,当存入对象时首先先算出此对象的hash值,看此对象属于哪个区域,并放进相应的

位置;当对集合中的元素进行删除或者比较的时候,直接算出所要进行比较或者删除的元素的hash值,看此hash值属

于哪个区域,直接去这个区域找这个元素即可,提高了效率。

第三:保证了存入集合中元素的唯一性。因为对于存入的元素先算hash值,跟集合中有的元素的hash值相等,则再调

用equals方法,若equals比较的也是相等,则视为相同元素,从而不再存入此集合,所以保证了集合元素的唯一性。

4.hashcode中算出的hash值可能会导致内存泄露。

因为在对于hashCode方法算hash值时,注意:当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的

那些参与计算哈希值的字段了,都则,对象修改以后的哈希值与最初存储进HashSet集合中的哈希值就不同了。那么

,当删除此元素时,由于算出的目前的hash值和存储进集合中的哈希值不一样,所以删除不掉此元素,这样就会导致

,不用的元素一直存在,释放不了内存空间,所以导致内存泄露。

例子:

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class HashCodeTest 
{
	public static void main(String[] args) 
	{
		// TODO Auto-generated method stub
		System.out.println("------------ArrayList-----------------");
		Collection collections=new ArrayList();
		HashCodeDemo hcd1=new HashCodeDemo(3,3);
		HashCodeDemo hcd2=new HashCodeDemo(5,6);
		HashCodeDemo hcd3=new HashCodeDemo(3,3);
		collections.add(hcd1);
		collections.add(hcd2);
		collections.add(hcd3);
		collections.add(hcd1);
		System.out.println(collections.size());//结果为4
		
		System.out.println("------------HashCode-----------------");
		Collection collections2=new HashSet();
		HashCodeDemo hcd4=new HashCodeDemo(3,3);
		HashCodeDemo hcd5=new HashCodeDemo(5,6);
		HashCodeDemo hcd6=new HashCodeDemo(3,3);
		collections2.add(hcd4);
		collections2.add(hcd5);
		collections2.add(hcd6);
		collections2.add(hcd4);
		System.out.println(collections2.size());//结果为2
		//注意此集合的长度,当没复写hashCode和equals的方法时结果为3,因为hashCode
		//默认的是对象的内存地址值得到的hash值,所以hcd4和hcd6是不同的元素,所以都被
		//加入进去了。
		//改变参与hash值运算的变量的值。 
		hcd4.x=7;
		collections2.remove(hcd4);
		System.out.println(collections2.size());//结果仍为2,因为并未去掉。	
	}
}
class HashCodeDemo
{
	public int x;
	public int y;
	public HashCodeDemo(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;
		HashCodeDemo other = (HashCodeDemo) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}
}

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

1.框架的概念

框架即为实现一个功能,但是这个功能内部调用的类或者其他的事物并不明确具体是什么,而是由以后具体用到的时

候再具体给出。这就是框架。

2.框架要解决的问题

第一:我在写框架时,你这个类可能还未被定义出来,那么该怎么调用你这样的一个类

第二:因为写框架的时候并不知道类名,所以,在程序中无法直接new某个类的实例对象了,那么该怎么对此类进行

各种操作呢?

3.要想解决以上问题就用反射来做

步骤:

第一,写一个配置文件,将以后要用到的类,可以写在配置文件中,用哪个就写哪个这样就不用再改框架中的代码了

。配置文件创建步骤:工程->new->file->文件名称:config.properties,这样将配置文件创建在了此工程下。用户

只要在运行的时候通过记事本修改配置文件中的信息即可。

第二:通过流和Properties类将配置文件加载进此工程的目录下并获取类名字符串即可。

第三:通过反射来得到类的字节码,然后通过Class类中的各种方法来对此类进行想要操作的动作。

例子:

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;
public class ReflectTest3 
{
	public static void main(String[] args)throws Exception
	{
		System.out.println("------------第一步加载进配置文件-----------------");
		//让输入流和文件进行相关联,来读取这个文件。
		InputStream is=new FileInputStream("config.properties");
		Properties pro=new Properties();
		//将文件加载进此类的目录中
		pro.load(is);
		is.close();//注意此处是关闭的是用到的系统的底层资源,而不是流。
		System.out.println("------------第二步得到配置文件的信息-----------------");
		//得到此配置文件中的信息
		String className=pro.getProperty("className");
		System.out.println("------------第三步通过反射来创建对象并进行操作-----------------");
		//Collection collections=new ArrayList();以前的做法
		//现在用反射的做法来创建集合对象,由于是无参的构造函数,所以可以
		//直接利用Class.newInstance()来创建对象。
		Collection collections=(Collection)Class.forName(className).newInstance();
		HashCodeDemo hcd1=new HashCodeDemo(3,3);
		HashCodeDemo hcd2=new HashCodeDemo(5,6);
		HashCodeDemo hcd3=new HashCodeDemo(3,3);
		collections.add(hcd1);
		collections.add(hcd2);
		collections.add(hcd3);
		collections.add(hcd1);
		System.out.println(collections.size());//根据配置文件中的集合类型来决定最后的集合长度		
	}
}
4.用类加载器的方式管理资源和配置文件

每一个框架都有配置文件,而加载配置文件的原理是:框架内部利用类加载器加载的配置文件,所以配置文件一般都是放在classpath路径下(因为类加载器是在加载的类的目录下加载配置文件的);若用eclipse开发程序,则配置文件一般放在source目录下即源文件目录下或者source子目录下(即子包),它会自动的将配置文件加载进classpath的目录下。

如下:InputStream is=ReflectTest3.class.getClassLoader().getResourceAsStream("具体目录名");
或者:InputStream is=ReflectTest3.class.getResourceAsStream("相对目录名或者具体目录名");

五、由内省引出JavaBean的讲解

内省的英文字母为:IntroSpector:检查、视察

1.定义
JavaBeen是一种特殊的java类,主要用于传递数据信息,这样java类中的方法

主要用于访问私有的字段,且方法名符合某种命名规则,即必须有以get和set为前缀的方法

例如:下面的类即为JavaBeen类,因为里面有以set和get为前缀的方法。

class Person
{
	private int age;
	public void setAge(int age)
	{
		this.age=age;
	}
	public int getAge()
	{
		return age;
	}
}

2.JavaBeen可以当做一般的类进行操作,而一般的类不一定可以当做JavaBeen类来进行操作因为只有当一般的类中有

分别以get和set为前缀的方法才可以。

3.JavaBeen的属性是什么呢?

JavaBeen的属性是去掉get和set前缀剩下的那部分,即为JavaBeen的属性,而不是类中的私有成员变量是它的属性。

所以即为设置和获取age属性值。

4.对于获取的属性,该如何用?

当得到的属性名的第二个字母是小写,而第二个字母是大写则把第一个字母也小写,

如:getAge去掉get为Age->age

当得到的属性名的第二个字母是大写,则并不把第一个字母变为小写,

如:getCPU和setCPU则属性名为CPU

当得到的属性名的第一个字母是小写,都是小写,则这就是属性名了,不再变大小写

如:gettime和settime,则属性名为time。

5.什么时候使JavaBeen呢?

如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBeen中,这种JavaBeen的实例对象通常称之为

值对象(Value Object,简称VO),这些信息在类中用私有字段来存储,如果读取或者设置这些字段的值,则需要通

过一些相应的方法来访问。

6.对JavaBean的简单内省操作
(1)JDK中提供了对JavaBeen进行操作的一些API,这套API就成为内省。如果对于私有的x,只是
通过getX方法来访问,有一定的难度,用内省这套API操作JavaBeen比用普通类的方式更方便。
(2)对于类中私有的属性进行取值
步骤:
第一,通过创建对象PropertyDescriptor来得到对于哪一个对象上的哪一个属性进行描述;
第二,通过此对象调用方法getReadMethod()来得到getX()(即X属性的读方法);
第三,用此方法调用invoke(类名)来说明此方法是作用于哪个对象上并调用此方法。
(3)对于类中的私有属性进行设值
步骤:
第一,通过创建对象PropertyDescriptor来得到对于哪一个对象上的哪一个属性进行描述;
第二,通过此对象调用方法getWriteMethod()来得到setX()(即X属性的写方法);
第三,用此方法调用invoke(类名,要设置的值)来说明此方法是给什么对象上的此属性赋值。
例子:

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
public class IntroSpectorTest 
{
	public static void main(String[] args) throws Exception
	{
		// TODO Auto-generated method stub
		 GetSetDemo gsd=new GetSetDemo(4,5);
		System.out.println("---------对x属性进行读取值---------------");
		//第一部分:创建PropertyDescriptor对象,传入的gsd.getClass()表示要被当做JavaBeen类的类
		//说明要进行描述的属性
		String propertyName="x";
		PropertyDescriptor pts=new PropertyDescriptor(propertyName,gsd.getClass());
		//第二部分:通过此对象调用getReadMethod()来得到对x属性的读方法
		Method methodRead=pts.getReadMethod();
		//第三部分:调用invoke(类名),来获取此属性的值
		System.out.println(methodRead.invoke(gsd));
		System.out.println("---------对x属性进行设置值---------------");
		//第一步创建PropertyDescriptor对象,说明要进行描述的属性
		PropertyDescriptor pts1=new PropertyDescriptor(propertyName,gsd.getClass());
		//第二部分:通过此对象调用getWriteMethod()来得到对x属性的写方法
		Method methodWrite=pts.getWriteMethod();
		//第三部分:调用invoke(类名),来设置此属性的值
		methodWrite.invoke(gsd,7);
		System.out.println(gsd.getX());
	}
}
class GetSetDemo
{
	private int x;
	private int y;
	public GetSetDemo(int x, int y) 
	{
		super();
		this.x = x;
		this.y = y;
	}
	public int getX() 
	{
		return x;
	}
	public void setX(int x) 
	{
		this.x = x;
	}
	public int getY() 
	{
		return y;
	}
	public void setY(int y) 
	{
		this.y = y;
	}	
}

7.使用BeanUtils工具包操作JavaBean

对于上面代码的那么多的步骤:即得到要操作的属性->得到对于操作此属性的各种方法->运用此方法。BeenUtils工具包将以上这样复杂的过程装换成了一步

例如:对于类中私有的属性进行取值:BeenUtils.getProperty(gsd,"x");

 对于类中的私有属性进行设值:BeenUtils.setProperty(gsd,"x","7");

注意:参数是字段名称和赋的值都是以字符串形式传入。

你可能感兴趣的:(java基础加强)