----------- 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 是一字节长,但是指令码的长度是变化的。每个指令有从 0 到 255(或十六进制的: 00 到FF)的一字节操作码,被参数例如寄存器或内存地址跟随。
boolean |
isPrimitive() |
注意:TYPE是一个常量,定义在如Integer这样的包装类型中,表示这个包装类所对应基本类型的字节码.所以: int.class==Integer.TYPE是true
Boolean.TYPE, Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE, Void.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 对象
href="#getConstructor(java.lang.Class...)" getConstructor(Class<?>... parameterTypes) |
同过Constructor类中的newInstance方法来new实例对象
href="#newInstance(java.lang.Object...)" newInstance(Object... initargs) |
实例:
反射比较消耗性能,耗时间.导致程序性能下降.所以Class中也提供了newInstance()方法
newInstance() |
创建此 Class 对象所表示的类的一个新实例。如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。
java.lang.reflect
类 Field
Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
Class类中的方法获取,Field对象.
href="#getField(java.lang.String)" getField(String name) |
|
Field[] |
getFields() |
//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方法可返回该类对象.
getMethod(String name, Class<?>... parameterTypes) |
|
Method[] |
getMethods() |
Method methodCharAt =String.class.getMethod("charAt",int.class);
通过Method自己调用方法,来进一步操作
invoke(Object obj, Object... args) |
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类]
@Test
public 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);//true
System.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 构造方法
@Test
public 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 方法
@Test
public 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 数组
@Test
public 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:[I
System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(a3.getClass().getSuperclass().getName());//java.lang.Object
//无论是一维,还是二维数组,他们归根结底都是个数组,是个对象,他们的*父类自然是Object
Object 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的内存泄漏
@Test
public 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
//结论,想删不能删,没用了,还占用内存,这样不断的日积月累,总有一天会出现内存泄漏的.
}
//********一个小框架,把程序要调用的类放在配置文件中,在源程序中不要出现这个类的名字.**********
@Test
public 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.ArrayList
String 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 {
//私有字段birthday
private 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地址
@Override
public 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中
@Override
public 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相对应的字段名--->如果第二个字母是小写,则把第一个字母变成小写的----age
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;
}
}
内省-----了解javaBean
java.beans
类 PropertyDescriptor
PropertyDescriptor(String propertyName, Class<?> beanClass) |
使用重构,所抽取的方法…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 {
@Test
public void Test() throws Exception {
//实例的同时,给构造方法传递两个值,分别给x,y赋值...
ReflectPoint pt1=new ReflectPoint(3,5);
//要求:获得这个"x"属性的值.
String propertyName="x";
//这里,可以使用重构,自动抽取方法,使得,一切都那么简单,爽快....Shift+Alt+M
System.out.println(getProperty(pt1, propertyName));
//提出来的方法,在下面.(见.获取属性方法)
//上面玩了,获取属性,下面,在这里就,玩下设置...
Object value=7;//来一个,值..
setProperties(pt1, propertyName, value);
//提出方法,(见.设置属性方法)
}
@Test
public 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;
}
}