1.首先了解Class类:java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class。
2.通过Class类可以得到关于这个类的各种信息。
3.一个Class对象代表内存中的一份字节码,每个类在内存中都有一份字节码用于创建该类的对象
4.获得Class对象(一份字节码)的方法:由类获得Class cl1=Date.class;对象调用.getClass()方法获得;有Class的静态方法获得Class.forName("java.util.Date");
5.第三种方法在反射中用的比较多,一般事先并不知道类的名字,类名以字符串的形式从配置文件中传递过来。接着获得该类的字节码,进而用字节码创建对象实现功能。
6.9个预定义的Class对象,包括8中基本数据类型对象和void类型的对象
源程序中出现的任意一种类型,都有对应的Class对象,例如:int[]、void
反射就是把java类中的各种成分映射成相应的java类。
表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应的类的实例对象表示,他们是Field、Method、Contructor、Package等等。也就是得到各种成分所对应的对象。
得到构造方法:得到一个构造方法:先获得Class类型对象(字节码)在根据相应的方法获得构造方法(根据参数的不同得到不同的构造方法)
Constructor cons=String.class.getConstructor(StringBuffer.class);
用构造方法得到对象,构造方法调用newInstance方法得到对象(Object类型的对象)
String st1=(String)constructor.newInstance(new StringBuffer("abc"));
Constructor 类有newInstance方法可以用来创建对象(先得到无参的构造方法再创建对象)
成员变量:若类Point有两个变量x、y,可以根据类所对应的字节码获得代表变量y的Field类型对象Field fieldY=Point.class.getField("y");
再根据代表变量的Field类型对象的方法fieldY.get(pt1)获得特定Point对象中变量y的值。
变量为private类型:Field fieldX=Point.class.getDeclaredField("x");可获得
设置为可访问:fieldX.setAccessible(true);
获得特定Point类型对象pt1中的变量值:fieldX.get(pt1)
问题:扫描一个对象的成员变量,把String类型变量中的字母替换为另一个字母
//扫描一个对象的成员变量,把变量中的'b'改为'a'
private static void changeStringValue(Object obj){
Field[] fields=ReflectPoint.class.getFields();//获得所有的变量
for(Field field : fields){
if(field.getType()==String.class)//Class类型的比较都是字节码
的比较用“==”,对象.getClass()获得对象的运行时类,field.getType()返回Field对象所表示字段的声明类型
{
String oldStr=(String)field.get(obj);
String newStr=oldStr.replace('b', 'a');
field.set(obj, newStr);
}
}
System.out.println(obj);
}
方法:用反射的方式从字节码中的到方法,用方法作用到某个对象。
//getMethod方法的参数为方法名和方法参数的字节码
Method methodCharAt=String.class.getMethod("charAt", int.class);
//methodCharAt对象通过invoke方法可以为某个对象调用此方法(前一个参数为要作用的对象,后一个参数为该方法的参数)
methodCharAt.invoke(arc1, 1);
当我们要执行某一类中的方法时,我们并不知道类的名字但我们知道类中有某一方法,可用反射实现,jdk1.4和jdk1.5之间invoke(arc1, 1);当第二个参数为数组类型时jdk1.5下回把数组拆成单个元素,在让类中的方法执行。
Jdk1.5中对于可变参数的方法一般会对数组拆包,我们若不想被拆可将数组强制转换为Object类型或在数组外面再包一层(Object类型)数组。一个数组也是Object类型的对象。
7.Properties类和HashMap类相似里面存储的内容都是键值对的形式存储,但不同的是Properties类通过流对象可以读取文件的内容和把内容写入文件,存储内容到文件的方法public void store(OutputStream out, String comments) ,
从文件中获得内容的方法public void load(InputStream inStream)
根据键值取出对象的方法,public String getProperty(String key)
如下示例从config.properties文件读取数据,获得类名用类名构造一个该类的对象。
文件里面的内容是 className=java.util.ArrayList。
InputStream is=new FileInputStream("config.properties");
Properties ps=new Properties();
ps.load(is);
is.close();
String className=ps.getProperty("className");
Class cl=Class.forName(className);
Collection collection=(Collection)cl.newInstance();
8.当我们要运行某个类时,类加载器会自动把类加载到内存中所以类加载器也可以把其他文件加载到内存中。获得某个类的类加载器用方法KuangJia.class.getClassLoader()
通过类加载器加载文件返回一个输入流类型注意类加载器是从项目的根目录开始搜索的
KuangJia.class.getClassLoader().getResourceAsStream("cn/itcust/day2/config.properties")。
还有另一个方法其实内部还是调用类的加载器只是这时路径相对于该类所在的目录。KuangJia.class.getResourceAsStream("config.properties")。
这种方法我们也可以用绝对路径这时是从项目的根目录开始搜索的
KuangJia.class.getResourceAsStream("/cn/itcust/day2/config.properties")。
9.javaBean的内省操作:对一个javabean对象里面的属性进行处理
首先要获得描述该属性的一个PropertyDescriptor类再根据该类获得对应与属性的get和set方法
获得属性值:
String propertyName ="x";
//根据属性名和对象名获得描述对象的一个类的对象,进而获得getX方法。
PropertyDescriptor pd =new PropertyDescriptor(propertyName,jbt.getClass());
Method methodGetX=pd.getReadMethod();
//根据该方法获得属性值,Method的对象可以调用invoke方法为某个对象调用此方法。
Object retVal=methodGetX.invoke(jbt, null);
我们可以封装成一个方法如下:只要根据一个javabean的一个对象和一个属性名就可以获得该属性的值。
private static Object getProperty(JavaBeanTest jbt, String
propertyName)throws Exception {
PropertyDescriptor pd =new
PropertyDescriptor(propertyName,jbt.getClass());
Method methodGetX=pd.getReadMethod();
Object retVal=methodGetX.invoke(jbt, null);
return retVal;
}
下面是为属性赋值:
Object setVal=8;
String propertyName ="x";
PropertyDescriptor pd1=new PropertyDescriptor(propertyName, jbt.getClass());
Method methodSetX=pd1.getWriteMethod();
methodSetX.invoke(jbt,setVal);
下面封装成一个方法,要传入三个参数javabean对象,属性名,要添加的属性值
private static void setProperty(JavaBeanTest jbt, String propertyName,Object setVal) throws Exception {
PropertyDescriptor pd1=new PropertyDescriptor(propertyName,
jbt.getClass());
Method methodSetX=pd1.getWriteMethod();
methodSetX.invoke(jbt,setVal);
}