『黑马程序员』---java--基础加强--反射+内省

来源:互联网 发布:四钻淘宝店值多少钱 编辑:程序博客网 时间:2024/06/10 04:50

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

学反射,要先学一个类:---->Class<T>

java.lang 
类 Class<T>

JDK1.0 

类型参数: 

T - 由此 Class 对象建模的类的类型。例如,String.class 的类型是 Class<String>。如果将被建模的类未知,则使用 Class<?>。

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。[九个预定义Class实例对象] 

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。 



三种方式获取类的字节码:

String str1="abc";

Class cls1=str1.getClass();

Class cls2=String.class;

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

System.out.println(cls1==cls2);//true

System.out.println(cls1==cls3);//true

三种方式,获得的字节码均相同.(确实是这样哈.不用验证也应该想到)每个类都有自己专属的字节码. 

字节码(Byte-code)是一种包含执行程序、由一序列 op 代码/数据对组成的二进制文件。字节码是一种中间码,它比机器码更抽象。它经常被看作是包含一个执行程序的二进制文件,更像一个对象模型。字节码被这样叫是因为通常每个 opcode 是一字节长,但是指令码的长度是变化的。每个指令有从 到 255(或十六进制的: 00 FF)的一字节操作码,被参数例如寄存器或内存地址跟随。


 boolean

isPrimitive() 
     判定指定的 Class 对象是否表示一个基本类型。


注意:TYPE是一个常量,定义在如Integer这样的包装类型中,表示这个包装类所对应基本类型的字节码.所以: int.class==Integer.TYPEtrue

Boolean.TYPECharacter.TYPEByte.TYPEShort.TYPEInteger.TYPELong.TYPEFloat.TYPEDouble.TYPEVoid.TYPE


Class中常用的方法:

public static Class<?> forName(String className);获取对象
例:Class c=Class.forName(“java.lang.System”);
public Field getField(String name); 返回一个 Field 对象,获取指定公共成员字段。
public Field[] getFields();返回所有可访问公共字段的对象数组
public Method getMethod(String name,Class<?>... parameterTypes);
返回一个 Method 对象,获取指定公共成员方法
public Method[] getMethods();返回所有公共 member 方法(以及所继承的方法)的对象的数组
public Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,获取指定公共构造方法
public Constructor<?>[] getConstructors();获取所有公有的构造方法的对象的数组

public PackagegetPackage();获取此类的包

public String getName();获取字符串形式的名称

public boolean isPrimitive();判定指定的Class 对象是否表示一个基本类型。

例:System.out.println(int.class.isPrimitive());


public String toString();将对象转换为字符串
public boolean isArray();判定此 Class 对象是否表示一个数组类;
例:System.out.println(int[].class.isArray());
public ClassLoader getClassLoader()返回该类的类加载器
public InputStream getResourceAsStream(String name) 查找具有给定名称的资源,返回的是InputStream


反射:

反射(Reflectiion):JavaBean是reflection的实际应用之一

 反射就是把Java类中的各种成分映射成相应的java类。

Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法

允许程序于执行期 Reflection APIs 取得任何已知名称之 class 的內部信息,(如:类中的组成部分:成员变量,方法,构造方法,包等等信息,而在反射中是将这些信息用一个个的类来表示,而Class类中就为之提供了相应方法来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,他们是Filed(变量) , Method(方法), Contructor(构造方法),  Package(包)等等


java.lang.reflect 
类 Constructor<T>


提供关于类的单个构造方法的信息以及对它的访问权限。Constructor[构造函数]


同过Class类中的getConstructor方法获得Constructor 对象

Constructor<T>

href="#getConstructor(java.lang.Class...)" getConstructor(Class<?>... parameterTypes) 
   返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

同过Constructor类中的newInstance方法来new实例对象

 T

href="#newInstance(java.lang.Object...)" newInstance(Object... initargs) 
      使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。


实例:


反射比较消耗性能,耗时间.导致程序性能下降.所以Class中也提供了newInstance()方法

 T

newInstance() 
 创建此 Class 对象所表示的类的一个新实例。(默认无参数的构造方法)

创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。


java.lang.reflect 
类 Field


Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。


Class类中的方法获取,Field对象.


  

 

 Field

href="#getField(java.lang.String)" getField(String name) 
     返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。

 Field[]

getFields() 
      返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

//Filed

ReflectPoint pt1=new ReflectPoint(3,5);

ReflectPoint pt2=new ReflectPoint(6,10);

Field fieldY=pt1.getClass().getField("y");

Field pt2fieldY=pt2.getClass().getField("y");

//fieldY的值是多少?5,!  fieldY不是对象身上的变量,

//而是类上,要用它去取某个对象上对应的值

System.out.println(fieldY.get(pt1));

System.out.println(fieldY.get(pt2));

//getField()不能取private的字段.这时要用暴力映射,getDeclaredField()方法

Field fieldX=pt1.getClass().getDeclaredField("x");

fieldX.setAccessible(true);

System.out.println(fieldX.get(pt1));


Exercise:



//建立某指定类的对象

ReflectPoint tr5=new ReflectPoint(1,2);

//使用自己编的改变方法

mychangeStringValue(tr5);

System.out.println(tr5);//打印结果演示

}

private static void mychangeStringValue(ReflectPoint tr5) throws IllegalArgumentException, IllegalAccessException {

//使用getFields()方法,返回该类中的所有字段,以数组的形式保存

Field[] fields=tr5.getClass().getFields();

//遍历该字段数组

for(Field field:fields){

//判断是否为String字段,这里要用"==",因为,因为是同一份字节码

if(field.getType()==String.class){

//获得,旧得值.

String oldValue=(String)field.get(tr5);

String newValue=oldValue.replace('b','c');

//set方法,彻底改掉

field.set(tr5,newValue);

}

}

}

 

java.lang.reflect 
类 Method


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





 

Class类中的getMethod方法可返回该类对象.

 Method

getMethod(String name, Class<?>... parameterTypes) 
          返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

 Method[]

getMethods() 
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

Method methodCharAt =String.class.getMethod("charAt",int.class);

 

通过Method自己调用方法,进一步操作

 Object

invoke(Object obj, Object... args) 
          对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

System.out.println(methodCharAt.invoke(str,3));//result:d

//调用CharAt方法同样可以像jdk1.4那样传递args参数System.out.println(methodCharAt.invoke(str,new   Object[]{3}));//result:d

 

深入理解Method,用反射凡是执行某个类中的main



进一步操作



//--------思考问题:怎么得到数组中的元素类型?

//数组中元素的类型可以得到,但是,整个数组的类型是得不到的.

Object[] b =new Object[]{"a",2,true};

//只能得到每一个具体元素的类型,不能得到整个数组的类型

System.out.println(b[0].getClass().getName());


package cn.itcast.day1;import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.Arrays;import org.junit.Test;public class ReflectTest {/**反射,就是把java类中的各种成分映射成相应的java类 * @param args *///Class 所有类的类[学反射先学Class类]@Testpublic void TestClass()throws Exception{  String str1="abc";//第一种方式,获得str1字节码所对应的实例对象Class cls1=str1.getClass();//对象.getClass();//第二种方式,获得str1字节码所对应的实例对象Class cls2=String.class;//类名.class;//第三种方式,获得str1字节码所对应的实例对象Class cls3=Class.forName("java.lang.String");//最常用的,Class.forName();//三种方法获得的字节码所对应的实例对象,均相同.System.out.println(cls1==cls2);//trueSystem.out.println(cls1==cls3);//true//用isPrimitive(),来判断,该字节码对象,是否为那----->九种基本类型//基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)//和关键字 void 也表示为 Class 对象。[九个预定义Class实例对象]System.out.println(cls1.isPrimitive());//false-----String不为基本类型,他是一个[对象]System.out.println(int.class.isPrimitive());//true----int为基本类型//TYPE是一个常量,定义在如Integer这样的包装类型中,表示这个包装类所对应基本类型的字节码System.out.println(int.class==Integer.TYPE);//true}//Constructor 构造方法@Testpublic void TestConstrucotr()throws Exception{//用Constructor,来实现----------new String(new StringBuffer("abc"))//同过Class类中的getConstructor(Class<?>... parameterTypes)方法获得Constructor 对象Constructor cons=Class.forName("java.lang.String").getConstructor(StringBuffer.class);//注意这里的StringBuffer是告诉程序选择那个构造方法//同过Constructor类中的newInstance(Object... initargs)方法来new实例对象//要时刻有编译时和运行时的概念String str=(String)cons.newInstance(new StringBuffer("abc"));//注意,这里的StringBuffer是,因为用着个构造方法,需要传递进去一个StringBuffer对象.//测试System.out.println(str.charAt(2));}//Filed字段public void TestFiled()throws Exception{//建立辅助类ReflectPoint的对象,其中构造方法是public ReflectPoint(int x, int y),x为私有的,y为公共的.ReflectPoint pt1=new ReflectPoint(3,5);ReflectPoint pt2=new ReflectPoint(6,10);//同过Class类中的getField(String name)方法来获得,Filed对象Field fieldY=pt1.getClass().getField("y");fieldY=pt2.getClass().getField("y");//fieldY的值是多少?是5,错!  fieldY不是对象身上的变量,//而是类上,要用它去取某个对象上对应的值System.out.println(fieldY.get(pt1));System.out.println(fieldY.get(pt2));//***注意:getField()不能取private的字段.会出现java.lang.NoSuchFieldException: x//这时要用暴力映射,用getDeclaredField()方法,该方法会获取该类中所有被declare[声明]的字段,只要你声明了,我就能拿。Field fieldX=pt1.getClass().getDeclaredField("x");//,获取了后,还需要设置Accessible[可进入的],才可以,打印出来,否则会报错can not access a member --- with modifiers "private"fieldX.setAccessible(true);//测试System.out.println(fieldX.get(pt1));//ok,打印出3//------EXercise:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"C"//先建立某指定类的对象ReflectPoint tr5=new ReflectPoint(1,2);//使用自己编的改变方法,见下方......mychangeStringValue(tr5);//打印结果测试System.out.println(tr5);}//Method 方法@Testpublic void TestMethod()throws Exception{//通过Class类中的getMethod(String name, Class<?>... parameterTypes)获取Method对象// 为了,调用String类中char charAt(int index)方法Method methodCharAt =String.class.getMethod("charAt",int.class);//建立String做测试.String str="abcd";//对象的再次深入理解:*****孝祥老师那列车死机刹车例子来说明,自己调用自己的功能,//司机只是通过踩刹车将信号发给列车,,最终还是列车自己把自己刹停了.人把门给关上了,门关上了,是门的动作.//***把变量搞成私有的,如果谁要操作这个变量,那么这个变量就在谁身上.这个方法就应该在谁身上.//这叫专家模式(谁又原有数据,谁就是干这个数据的专家,那么这个方法就应该跟这个谁)***//如果传递给Method对象的invoke()方法的第一个参数为null,这就说明该Method对象对应的是一个静态方法//[反过来说,需要传递对象的,都是,需要在该对象的基础上被调用的方法] 没有对象就可以直接调用的不就是,静态方法嘛.//简单说,静态方法,不用对象调用....System.out.println(methodCharAt.invoke(str, 3));//result:d//调用CharAt方法同样可以像jdk1.4那样传递args参数System.out.println(methodCharAt.invoke(str, new Object[]{3}));//result:d//------深入理解Method,用反射凡是执行某个类中的main方法.------//jdk1.4与1.5的invoke方法的区别://常规调用,并传递参数....TestArguments.main(new String[]{"1","hello","2"});//反射调用--通过本主函数的args参数,传递进来所要执行的某个类的类名String startingClassName="cn.itcast.day1.TestArguments";//通过,类名先获得到该类字节码的对象,再通过getMethod获得,Method对象.******这里注意:参数类型一定要和,所调的类的参数类型一致.Method mainMethod=Class.forName(startingClassName).getMethod("main", String[].class);//调用该方法,,,这里,因为,"main"方法是静态(static)的,所以不用传递对象.//***注意,这里,1.5为了兼容1.4版本,当传进去一个对象数组时,他会自动拆包.这里,只单传一个String[]内包含3个元素,程序会被认为是传递了三个参数*****mainMethod.invoke(null,new Object[]{new String[]{"2","Hello","2"}});//解决办法:在外边给他加一个包,让他去拆得了[该main方法,规定传递一个String[]参数]//当然,还有第二中解决方法:把他强制扭转成上帝类(看他敢不敢拆),这样的话, 编译器就不会,把他当数组看待了.也就自然不拆包了.mainMethod.invoke(null,(Object)new String[]{"2","Hello","2"});}//Array 数组@Testpublic void TestArray(){//*验证:具有----->相同[维数]和元素类型的数组<----属于同一个类型,即具有相同的Class实例对象.int[] a1=new int[]{1,2,3};int[] a2=new int[4];int[][] a3=new int[2][3];String[] a4=new String[]{"a","b","c"};System.out.println(a1.getClass()==a2.getClass());//true----[同一份字节码]//System.out.println(a1.getClass()==a3.getClass());//false//System.out.println(a1.getClass()==a4.getClass());//false//*验证完毕,证据确凿//数组的Class实例对象的----getSuperClass()----方法返回的父类为Object类对应的Class//说明,他们都是Object的小弟,都是对象.System.out.println(a1.getClass().getName());//result:[ISystem.out.println(a1.getClass().getSuperclass().getName());//java.lang.ObjectSystem.out.println(a3.getClass().getSuperclass().getName());//java.lang.Object//无论是一维,还是二维数组,他们归根结底都是个数组,是个对象,他们的顶级父类自然是ObjectObject aObj1=a1;Object aObj2=a4;//Object[] aObj3=a1;//因为:a1数组中装的是int基本类型,int不是个对象,所以,他不能转换成Object数组Object[] aObj4=a3;//二维数组中装的是一维数组,一维数组是Object的(是个对象),所以通过Object[] aObj5=a4;//一维数组中装的是String,非基本类型,String是Object的(是个对象),所以通过//为了方便查看数组中的元素,可以通过Arrays中的asList(),将其元素转到List集合中,从而打印出来System.out.println(Arrays.asList(a4));//将String数组转成List打印出来是[a, b, c],成功System.out.println(Arrays.asList(a1));//将int数组转成List打印出来是[[I@1888759],表面上失败//**********为什,没有像String数组那样,将数组中的每个值打印呢?**********//因为,1.5版本中是asList(T... a),1.4版本中是asList(Object[] a),1.5为了兼容1.4,所以还保留了1.4//的传参方式.-我们传递进去的是一个数组,但这个数组不属于Object[],所以,1.4处理不了,就交给1.5处理了.//1.5确实会把,这个int数组转成list集合,但,1.5是把int[]看成一个参数.将int[]整体转存到了list集合中的.//--------演示Array类的应用:System.out.println("*****************");Object o1="abcdefg";int[] o2=new int[]{1,34,234};printObject(o1);printObject(o2); //********思考问题:怎么得到数组中的元素类型?**********//数组中元素的类型可以得到,但是,整个数组的类型是得不到的.Object[] b =new Object[]{"a",2,true};//只能得到每一个具体元素的类型,不能得到整个数组的类型System.out.println(b[0].getClass().getName());//java.lang.String}//以下为辅助方法,和类//演示Array类的应用,涉及到//运用反射,编写一个方法,能够识别数组,如果是数组,就自动遍历并打印,如果不是数组,直接打印private static void printObject(Object obj) {//判断传递进来的参数是否为数组Class clazz=obj.getClass();//如果是数组,我就拆开,遍历if(clazz.isArray()){//Array.getLength(Object array) 以 int 形式返回指定数组对象的长度。int length=Array.getLength(obj);//用for循环遍历for(int i=0;i<length;i++){//Array.get(),方法得到元素,并打印System.out.println(Array.get(obj, i));}//不是数组的话,直接打印}else{System.out.println(obj);}}//------Filed,Exercise涉及到 @SuppressWarnings("unused")private static void mychangeStringValue(ReflectPoint tr5) throws IllegalArgumentException, IllegalAccessException {//使用---getFields()-----方法,返回该类中的所有字段,以数组的形式保存Field[] fields=tr5.getClass().getFields();//遍历该字段数组for(Field field:fields){//判断是否为String字段,这里要用"==",因为,因为是同一份字节码if(field.getType()==String.class){//field.getType().equals(String.class)//获得,旧值.String oldValue=(String)field.get(tr5);//将临时旧值中的数值替换---replace.replace(oldChar, newChar)[取代,替换]------更换所有的旧值String newValue=oldValue.replace('b','c');//最后用set方法,作用到实际类中,彻底改掉field.set(tr5,newValue);}}}}//------深入理解Method,涉及到class TestArguments{public static void main(String[] args){for(String arg:args){System.out.println(arg);}}}


package cn.itcast.day1;import java.io.FileInputStream;import java.io.InputStream;import java.util.Collection;import java.util.HashSet;import java.util.Properties;import org.junit.Test;public class ReflectTest2 {//先,了解下ArrayList和HashSet的区别------以及HashSet的内存泄漏@Testpublic void Test1(){//其中,会涉及到一个面试题:hashcode方法的作用.//面向接口编程或者,面向父类编程//复习下,ArrayList中元素是有序的,可以重复,底层机构是有索引的数组结构....Collection collections=new HashSet();//是//实例对象,构造方法,对字段赋值ReflectPoint pt1=new ReflectPoint(3,3);ReflectPoint pt2=new ReflectPoint(5,5);//元素和pt1中一样.(对象引用地址不同)ReflectPoint pt3=new ReflectPoint(3,3);//HashSet,底层判断元素重复,是运用hashcode和equals//两种方法来区别,hashcode一般根据对象引用地址算出,所以,想要排除pt3和pt1重复,就要复写方法.//调用4个add方法collections.add(pt1);collections.add(pt2);collections.add(pt3);collections.add(pt1);//HashSet中添不进去.System.out.println(collections.size());//复写两个方法后,result为:2//**************************************************************************//注意:当一个对象存储到hashSet中后,就别去修改,其中参与hash值运算的那些成员----------//---测试,修改被拿来计算hashcode的字段.是否会出现**内存泄漏**,忽略问题.//修改掉,被拿来计算hashcode的一个字段pt1.y=7;//用remove方法,移除该对象.collections.remove(pt1);//验证,整个集合的大小,来判断,是否pt1,已经移除System.out.println(collections.size());//发现,该集合大小仍旧是原来的大小2//结论,想删不能删,没用了,还占用内存,这样不断的日积月累,总有一天会出现内存泄漏的.}//********一个小框架,把程序要调用的类放在配置文件中,在源程序中不要出现这个类的名字.**********@Testpublic void Test2()throws Exception{//将上面的操作,改为用[[[[反射的方式]]]]]//其实,就是在程序中不要出现,那个类的具体名字,而是从一个配置文件(File[config.properties])中读取出来 //加载Properties文件,第一种[1]方法-----------直接用io流读//一定要记住,用完整的路径,但完整的路径不是硬写出来的,而是通过运算得出来的//如:getRealPath();//金山词霸/内部路径InputStream ips=new FileInputStream("config.Properties");//需要抛异常//加载Properties文件,第二种[2]方法------------用类加载器//最常见的,得到资源文件的方式----类加载器------,他不能替代上面那个(因为上面那个还可以搞Output往里写).//类加载器,加载的时候,是直接从classPath下搜找(本机是bin文件夹)注意cn前不用加"/"ReflectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");//类加载器,加载配置文件,很方便(但,是只读哦),直接可以随着加载类的同时加载.[框架中大部分用的是类加载器加载配置文件]//加载Properties文件,第三种[3]方法(第2种的升级版)//和,上面功能一样,但简洁了代码,,,,,(孝祥老师倒卖可乐的例子)Class类中直接就提供了这个累加器,加载其他文件的方法.//该方法,很聪明,见参数中没有"/"开头,就判断他是相对路径,直接从自己所属的包下开始加载.//当然,该包下再建一个包resources的话,只要告诉他,相对于他所属包下的一个包里就成了,如下.ReflectTest2.class.getResourceAsStream("resources/config.properties");//嘿嘿,有相对路径就有绝对路径.只要,在路径前面加上"/"就可以告诉他要走绝对路径了.//记着,写绝对路径时,就要从根目录写起了....[和上面那个相对的效果一样]ReflectTest2.class.getResourceAsStream("/cn/itcast/day1/resources/config.properties");//Properties对象,就等效于一个hashMap.....但他在hashMap基础上,还扩展了一点功能//他可以,把自己内存中的键值对存到硬盘的文件上去,他还可以在初始化的时候,从一个文件中将键值对加载进来//hashMap需要手工一个个导入,而Properties就很省劲了.Properties props=new Properties();//*******这里设计到Properties类.很中要的哦...props.load(ips);//将配置文件加载到props对象中.//良好的习惯,用完就关门.否则会有一点点内存泄漏*****(这个内存泄漏不是这个对象不被释放,//而是这个对象关联的系统资源没有被释放)******ips.close();//自己在被垃圾回收之前,先把其关联的系统资源干掉[玩C++经常做的事,+死之前不要有牵挂+]//通过getProperty(key),在配置文件键值对className=java.util.ArrayList中,的到java.util.ArrayListString className=props.getProperty("className");//得到要建立的指定类Collection collections=(Collection) Class.forName(className).newInstance();ReflectPoint pt1=new ReflectPoint(3,3);ReflectPoint pt2=new ReflectPoint(5,5);ReflectPoint pt3=new ReflectPoint(5,5);collections.add(pt1);collections.add(pt2);collections.add(pt3);collections.add(pt1);System.out.println(collections.size());//因为配置文件中指的是ArrayList//所以,反射过来,建立的集合,也是ArrayList,自然其的大小为4,ArrayList中允许有重复元素哈.//当然,要是将配置文件中的值该为HashSet的话,最后出来的size就是2...(我们已经复写了hashcode和equals哦)}}


package cn.itcast.day1;import java.util.Date;//辅助类public class ReflectPoint {//私有字段birthdayprivate Date birthday=new Date();public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}//私有字段"P"private int p;public int getP() {return p;}public void setP(int p) {this.p = p;}//字段public String str1="ball";public String str2="basketball";public String str3="itcast";//需要覆盖,toString方法,否则打印出去的是cn.itcast.day1.ReflectPoint@6e1408地址@Overridepublic String toString(){return str1+":"+str2+":"+str3;}private int x;public  int y;//创建构造方法可以使用快捷键Shift+Alt+S中public ReflectPoint(int x, int y) {super();this.x = x;this.y = y;}//自动,覆写hashcode和equals方法.快捷键Shift+Alt+S中@Overridepublic int hashCode() {final int prime = 31;int result = 1;//复写后,计算hashcode用到x,y的值...这样才可以保证唯一性和杜绝不按对象内存地址计算hashcode//************************************************************//值得注意一下:当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算//哈希值的字段了(如,这里的x,y),否则,对象修改后的哈希值与最初存储进HashSet集合中时的哈希//值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去HashSet集合//中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,//从而造成内存泄漏的问题.//***************************result = prime * result + x;//字段 x参与hash值运算result = prime * result + y;//字段 x参与hash值运算return result;}@Override//注解---Override[覆盖],作用可以检查人工抒写的代码到底是否正确的覆盖了父类的方法..public boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;ReflectPoint other = (ReflectPoint) obj;if (x != other.x)return false;if (y != other.y)return false;return true;}//自动生成set,get方法.来操作字段...一般字段都为private//这样,就符合javabean的格式了....//getAge相对应的字段名--->如果第二个字母是小写,则把第一个字母变成小写的----agepublic 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;}}


内省-----了解javaBean

java.beans 
类 PropertyDescriptor

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

使用重构,所抽取的方法Shift+Alt+M

private static void getProperty(ReflectPoint pt1, String propertyName)

throws IntrospectionException, IllegalAccessException,

InvocationTargetException {

*PropertyDescriptor pd=new PropertyDescriptor(propertyName, pt1.getClass());

*Method methodGetX=pd.getReadMethod();

*Object retVal=methodGetX.invoke(pt1);//适当记一些.大师写的变量名字




System.out.println("*****A*******p******a******c******h*****e**");

//BeanUtils,直接提供了,getProperty(bean, name)获取指定属性值的方法.

 

System.out.println(BeanUtils.getProperty(pt1, "x").getClass().getName());

//这里,通过,对获取后的值,进行字节码,名字判定出,java.lang.String

//所以类,这里,就是BeanUtils的好处了,,它可以给我们自动类型转换.

//下面我们就,用一个Date的实例来,验证下把.....自动类型转换.......,String字符串为主要转换类型.

//Beanutils,直接提供了BeanUtils.setProperty(bean, name, value),可以直接设置属性值.

BeanUtils.setProperty(pt1, "x""9");

System.out.println(getProperty(pt1, propertyName));

//上面,BeanUtils的第一个好处,,自动类型转换..下面就说下,他的第二个好处[可以对属性链进行值的操作]

//提前,ReflectPoint,建立了一个Date字段,并符合javabean...,而且,new了对象,因为要对Date下的time进行设置..

BeanUtils.setProperty(pt1, "birthday.time","111");

//同样也能取出.

System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));//result:111

/*此外,还有-----copyProperties(Object dest, Object orig),将一个对象上的属性,拷贝到另一个对象身上去.rig[]

 * ------- Map<String,String>   describe(Object bean),将一个bean,转换成Map

 * -----populate(Object bean, Map<String,? extends Object> properties),Map转换成bean

 *///还有好多方法,自己去看文档。。。。

/*再此外setProperty(),还可以对Map的值进行设置.

 * 

Map map={name:"xxx",age:18};//这是java7的新特性,Map可以,这样赋值...

BeanUtils.setProperty(Map, "name", "yyy");

*/

//最后,,,,在补充一点...PropertyUtils...

//BeanUtils是以字符串的形式,javabean进行操作.传值的时候,给他String,他给你转成相对应的属性值类型.

//PropertyUtils以属性本身的类型,javabean进行操作,必须给他和属性值相同的类型.才可以.

package cn.itcast.day1;import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.HashMap;import java.util.Map;import org.apache.commons.beanutils.BeanUtils;import org.apache.commons.beanutils.PropertyUtils;import org.junit.Test;//内省,,,引出javabean规范......主要是作用于,传递值的操作.[反射的一个特例]//这里,也提出了,apache好心部落给我们提供的BeanUtils工具包,从而更方便我们的操作..站在巨人的肩膀上行走..../* * 会结识到的单词有:Apache[阿帕奇]Property[属性] Descriptor[描述符] */public class IntrospectorTest {@Testpublic void Test() throws Exception {//实例的同时,给构造方法传递两个值,分别给x,y赋值...ReflectPoint pt1=new ReflectPoint(3,5);//要求:获得这个"x"属性的值.String propertyName="x"; //这里,可以使用重构,自动抽取方法,使得,一切都那么简单,爽快....Shift+Alt+MSystem.out.println(getProperty(pt1, propertyName));//提出来的方法,在下面.(见.获取属性方法)//上面玩了,获取属性,下面,在这里就,玩下设置...Object value=7;//来一个,值..setProperties(pt1, propertyName, value);//提出方法,(见.设置属性方法)}@Testpublic void TestApache()throws Exception{//这里,就要开始用高新技术了...嘿嘿,站在巨人的肩膀上行走.....Apache谢谢您.ReflectPoint pt2=new ReflectPoint(3,5);System.out.println("*****A*******p******a******c******h*****e**");//BeanUtils中,直接提供了,getProperty(bean, name)获取指定属性值的方法.System.out.println(BeanUtils.getProperty(pt2, "x"));//Beanutils中,直接提供了BeanUtils.setProperty(bean, name, value),可以直接设置属性值.BeanUtils.setProperty(pt2, "x", "9");//字段X为int类型//BeanUtils的好处了,对,它可以给我们自动类型转换.--常用于web表单提交.他以String字符串为主要转换类型.//*******这里注意下,他只支持八种基本类型自动转换.----如果涉及到其他类型需要,进行自定义注册.//上面,是BeanUtils的第一个好处,能,自动类型转换..下面就说下,他的第二个好处[可以对属性链进行值的操作]//提前,在ReflectPoint中,建立了一个Date字段,并符合javabean...,而且,也new了对象,因为要对Date下的time进行设置..BeanUtils.setProperty(pt2, "birthday.time","111");//给birthday对象下的time进行赋值//同样也能取出.System.out.println(BeanUtils.getProperty(pt2, "birthday.time"));//result:111/*此外,还有-----copyProperties(Object dest, Object orig),将一个对象上的属性,拷贝到另一个对象身上去.rig[源] * ------- Map<String,String>   describe(Object bean),将一个bean,转换成Map * -----populate(Object bean, Map<String,? extends Object> properties),将Map转换成bean *///还有好多方法,自己去看文档。。。。//再此外setProperty(),还可以对Map的值进行设置.//Map<String, Integer> map={name:"zxx",age:18};//这是java7的新特性,Map可以,这样赋值...Map<String,Integer> map=new HashMap<String,Integer>();map.put("zxx",5);BeanUtils.setProperty(map, "name", "yyy");System.out.println(BeanUtils.getProperty(map, "zxx"));System.out.println(BeanUtils.getProperty(map, "name"));//最后,,,,在补充一点...Apache的------>PropertyUtils...//BeanUtils是以字符串的形式,对javabean进行操作.传值的时候,给他String,他给你转成相对应的属性值类型.//PropertyUtils以属性本身的类型,对javabean进行操作,必须给他和属性值相同的类型.才可以.PropertyUtils.setProperty(pt2, "x", 9); System.out.println(PropertyUtils.getProperty(pt2, "x").getClass().getName());//java.lang.Integer}//使用重构,抽取方法…Shift+Alt+M,,,(获取属性方法)private static void setProperties(ReflectPoint pt1, String propertyName,Object value) throws IntrospectionException,IllegalAccessException, InvocationTargetException {//主题//首先,用PropertyDescriptor[属性描述符],描述 Java Bean 通过一对存储器方法导出的一个属性。 PropertyDescriptor pd2=new PropertyDescriptor(propertyName, pt1.getClass());//其次,在利用该对象中的getWriteMethod()方法,获取相应的方法.这里是set,写入..Method methodSetX=pd2.getWriteMethod();//再用,该方法,中的调用,来彻底实现操作.methodSetX.invoke(pt1,  value);//部分}private static Object getProperty(ReflectPoint pt1, String propertyName)throws IntrospectionException, IllegalAccessException,InvocationTargetException {//主题//PropertyDescriptor pd=new PropertyDescriptor(propertyName, pt1.getClass());//Method methodGetX=pd.getReadMethod();//Object retVal=methodGetX.invoke(pt1);//适当记一些.大师常写的变量名字.例如:retVal,代表返回的值.//部分//下面的代码,和上面的主体部分,得到的----结果一样----[这里,就是了解下哈....]//孝祥老师以前总用下面这个,现在有简单的了,就不用了,不过这里还是要提以下,嘿嘿.(对javaBean的复杂内省操作.)如下//以下这个代码就是,典型的对集合进行遍历,并寻找到自己需要的那个元素,进行对其相关的操作.//主题//首先通过,Introspector[内省],下的getBeanInfo()静态方法,返回一个BeanInfo对象.BeanInfo beanInfo=Introspector.getBeanInfo(pt1.getClass());//其次,再从beanInfo下,找个获取属性的方法**但这里---只有获取[全部]属性的方法,所以,没办法只能进行遍历,寻值.了呗..PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors();//为了最后,能返回retVal值,所以,不能定义在for局部中.嘻嘻,你知道的把..Object retVal=null;//遍历,所有的属性,开始..for(PropertyDescriptor pd:pds){//判断该属性是否为,自己需要的.if(pd.getName().equals(propertyName)){//是的话,就获取方法.Method methodGetX=pd.getReadMethod();//调用,获取属性值.retVal=methodGetX.invoke(pt1);break;}}//部分return retVal;}}



0 0
原创粉丝点击