您的位置:首页 > 职场人生

黑马程序员_Java高新技术——反射和内省(第8篇)

2014-08-13 12:46 531 查看
----------------------
ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

一、简介

    所谓反射,就是将一个Java类中的各个成分映射成相应的Java类。要理解反射,首先要具备Java中万物皆对象的思想,要明白Java类中的各个成分也是对象,比如方法、字段构造函数等等都是,就连类本身也是Class类,即使类类。所谓的类类(Class),就是Java类在内存中的字节码文件,Java可以根据类的字节码文件创建若干类的对象。

    内省:内省的英文为introspector,字面意思是内部检查,顾名思义,其主要用于对JavaBean进行操作。那么这里就要了解何为JavaBean。JavaBean是一中特殊的类,其里面的方法的名称符合某种特定的规则,比如获取这个类的age属性的方法必须public int getAge(){return age;}的形式,其修改age属性就必须为public void setAge(int
age){this.age = age}的形式。J
4000
avaBean可以当成一个普通的Java类来操作,但是我是要当做JavaBean来操作呢?自然是有些额外的好处而已。普通的类不一定可以当成JavaBean来操作,但是JavaBean一定可以当成普通的类来操作。一般如果要在两个模块之间传递消息,便可以把这些消息封装在JavaBean中,,这样的JavaBean的实例对象通常称之为值对象(Value-Object,简称VO)。

二、反射实例

    对于反射,首先要得到类型对应的字节码文件,有了字节码文件才能够通过反射提取各个类的成分对象,才能有后续的操作。

    如何得到各个字节码对应的实例对象(Class类)?一般有三种方式:--类名.class--对象.getClass()--Class.forName("类名")

//通过反射得到String类的String(StringBuilder builder)构造函数,并创建String对象,打印出来

import java.lang.reflect.*;
class ReflectTest
{
public static void main(String[] args)throws Exception
{
//通过字节码文件对象得到指定构造函数对象(参数为指定字节码文件所表示的类型)
Constructor con = String.class.getConstructor(StringBuilder.class);
//根据构造函数对象,创建类,返回是Object类型,需强转
String str = (String)con.newInstance(new StringBuilder("asjdadnajdka"));
System.out.println(str);
}
}
//通过反射得到对象指定字段的值
import java.lang.reflect.*;
class ReflectTest
{
public static void main(String[] args)throws Exception
{
ReflectPoint rp = new ReflectPoint(3);
//通过字节码文件对象得到指定字段类对象
//Field类表示字段类,字段类对象表示这个字段所在的类的任何一个对象中的这个字段,他是一个综合体,并不是一个具体的指向
Field fieldX = ReflectPoint.class.getField("x");
int value = (int)fieldX.get(rp);
System.out.println(value);
}
}
class ReflectPoint
{
public int x;
ReflectPoint(int x)
{
this.x = x;
}
}
//通过反射得到String类的char charAt(int index)函数,并执行指定String对象的此方法
import java.lang.reflect.*;
class ReflectTest
{
public static void main(String[] args)throws Exception
{
String s = "abc";
//反射得到指定方法
Method charAtMethod = String.class.getMethod("charAt", int.class);
//执行指定对象的这个方法
char ch = (char)charAtMethod.invoke(s, 1);
System.out.println(ch);
}
}注:如果传递给Method对象的invoke()方法的第一个参数为null,这说明该Method对象对应的是一个静态方法

//综合练习,将一个对象中的所有String类型的变量中的字符'b'全部换成字符'k'
import java.lang.reflect.*;
class ReflectStringTest
{
public static void main(String[] args)throws Exception
{
//所要操作的对象
ReflectPoint rp = new ReflectPoint(3,5);
System.out.println(rp.toString());
rp = (ReflectPoint)fieldStringReplace(rp);
System.out.println(rp.toString());
}
public static Object fieldStringReplace(Object obj)throws Exception
{
//根据对象获得字节码文件,根据字节码文件获得所有字段类数组
Field[] fiels = obj.getClass().getDeclaredFields();
for(Field field : fiels)
{
//遍历字段是否是字符串类型
if(field.getType() == String.class)
{
//替换字符
field.setAccessible(true);
String oldString = (String)field.get(obj);
String newString = oldString.replace('b', 'k');
field.set(obj, newString);
}
}
return obj;
}
}
class ReflectPoint
{
public int x;
private int y;

String a = "abc";
String b = "bcd";
String c = "cbcabe";
public String d = "bsksdjsbsdsbsdisbfdbdsbbbdksd";
private String e = "sdsbbbbadsaaaabb";

ReflectPoint(int x, int y)
{
this.x = x;
this.y = y;
}
public String toString()
{
return a + " : "+ b + " : " + c + " : " + d + " : " + e;
}
}

    在上面的例子中,我们反射的不管是字段还是方法,都是公共的public的,像private之类私有的元素便不能通过这种普通的方式来做,此时就出现了一种特殊的反射,称之为——暴力反射。

    暴力反射与普通反射其实理解起来原理是一样的,都是使用Java提供的函数来完成,只不过函数的选择和用法上稍许不同。
//暴力反射出对象的私有字段

import java.lang.reflect.*;
class BaoLiReflect
{
public static void main(String[] args)throws Exception
{
//暴力反射
ReflectPoint rp = new ReflectPoint(5);
//私有的必须用这个函数
Field fieldY = ReflectPoint.class.getDeclaredField("y");
//设置是否允许
fieldY.setAccessible(true);
int y = (int)fieldY.get(rp);
System.out.println("y = " + y);
}
}
class ReflectPoint
{
private int y;
ReflectPoint(int y)
{
this.y = y;
}
}
三、内省的操作方式
对JavaBean的操作方式有两种

--步骤:1.new PropertyDescriptor("属性名", 属性所在的字节码文件——Xxx.class);

        2.调用PropertyDescriptor的读写方法,得到get set的方法对象

        3.操作得到的方法对象,得到或修改属性值。

--步骤:1.BeanInfo bin = Introspector.getBeanInfo(类的字节码文件);

        2.PropertyDescriptor[] pd = bin.getPropertyDescriptor();

        3.迭代比较得到指定的PropertyDescriptor对象

        4.根据上一种方式的2,3操作

如下例子:

import java.lang.reflect.*;
import java.beans.PropertyDescriptor;
import java.beans.Introspector;
import java.beans.BeanInfo;
class ReadJBPointX
{
public static void main(String[] args)throws Exception
{
//有这样一个类对象中,有一个属性名为"x"
//分析,那就有一个方法为getX()
JBPoint p = new JBPoint(3);
String propertyName = "x";

//普通反射的方法
Method getXMethod = p.getClass().getMethod("getX");
System.out.println(getXMethod.invoke(p));

//第一种方式
//属性描述类,参数属性名和哪个类的(字节码文件)属性
PropertyDescriptor pd = new PropertyDescriptor(propertyName, p.getClass());
Method getMethod = pd.getReadMethod();
System.out.println(getMethod.invoke(p));

Method setMethod = pd.getWriteMethod();
setMethod.invoke(p, 5);
System.out.println(getMethod.invoke(p));

//第二种方式
//复杂的内省操作方法
BeanInfo bin = Introspector.getBeanInfo(p.getClass());
PropertyDescriptor[] pds = bin.getPropertyDescriptors();
for(PropertyDescriptor pdm : pds)
{
if(pdm.getName().equals(propertyName))
{
Method getMethodm = pdm.getReadMethod();
System.out.println(getMethodm.invoke(p));
break;
}
}
}
}
class JBPoint
{
private int x;
JBPoint(int x)
{
this.x = x;
}
public int getX()
{
return x;
}
public void setX(int x)
{
this.x = x;
}
}
----------------------
ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: