1. 修改成员值:
尽管直接存取类的域成员是不被鼓励的,但仍可以直接存取公开的域成员,甚至也可以通过反射机制来存取私有域成员。下面以一个实例来说明,首先编写一个TestField类。
package ysu.hxy; public class TestField { public int testInt; public String testString; public String toString() { return testInt + ":" +testString; } }
下面的范例利用反射机制动态加载类来存取域成员:
package ysu.hxy; import java.lang.reflect.Field; public class AssignFieldDemo { public static void main(String[] args) { try { Class c = Class.forName(args[0]); Object targetObj = c.newInstance(); //返回域成员 Field testInt = c.getField("testInt"); testInt.setInt(targetObj,99); Field testString = c.getField("testString"); testString.set(targetObj,"caterpillar"); System.out.println(targetObj); } catch(ArrayIndexOutOfBoundsException e) { System.out.println("没有指定类"); } catch(ClassNotFoundException e) { System.out.println("找不到指定的类"); } catch(SecurityException e) { e.printStackTrace(); } catch(NoSuchFieldException e) { System.out.println("找不到指定的域成员"); } catch(InstantiationException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); } } }运行结果:
D:\hxy>java ysu.hxy.AssignFieldDemo ysu.hxy.TestField99:caterpillar
如果有必要,也可以通过反射机制存取私有的域成员,如:
Field privateField = c.getDeclaredField("privateField"); privateField.setAccessible(true); privateField.setInt(targetObj,99);2.再看数组对象:
在Java中数组也是一个对象,也会有一个Class实例来表示它。如下:
package ysu.hxy; public class ArrayDemo { public static void main(String[] args) { short[] sArr = new short[5]; int[] iArr = new int[5]; long[] lArr = new long[5]; float[] fArr = new float[5]; double[] dArr = new double[5]; byte[] bArr = new byte[5]; boolean[] zArr = new boolean[5]; String[] strArr = new String[5]; System.out.println("short 数组类:" + sArr.getClass()); System.out.println("int 数组类:" + iArr.getClass()); System.out.println("long 数组类:" + lArr.getClass()); System.out.println("float 数组类:" + fArr.getClass()); System.out.println("double 数组类:" + dArr.getClass()); System.out.println("byte 数组类:" + bArr.getClass()); System.out.println("boolean 数组类:" + zArr.getClass()); System.out.println("String 数组类:" + strArr.getClass()); } }运行结果:
D:\hxy>java ysu.hxy.ArrayDemoshort 数组类:class [Sint 数组类:class [Ilong 数组类:class [Jfloat 数组类:class [Fdouble 数组类:class [Dbyte 数组类:class [Bboolean 数组类:class [ZString 数组类:class [Ljava.lang.String;
若要使用反射机制动态生成数组,可以使用java.lang.reflect.Array来协助。下面的这个范例示范了如何生成String数组:
package ysu.hxy; import java.lang.reflect.Array; public class NewArrayDemo { public static void main(String[] args) { Class c = String.class; Object objArr = Array.newInstance(c,5); for(int i = 0;i < 5;i++) { Array.set(objArr,i,i+""); } for(int i = 0;i < 5;i++) { System.out.print(Array.get(objArr,i) + " "); } System.out.println(); String[] strs = (String[]) objArr; for(String s : strs) { System.out.print(s+ " "); } } }Array.newInstance()的第一个参数指定元素类型,而第二个参数指定数组长度。此方法还有另一个版本,用于创建二维数组,如下:
package onlyfun.caterpillar; import java.lang.reflect.Array; public class NewArrayDemo2 { public static void main(String[] args) { Class c = String.class; // 打算建立一个3*4数组 int[] dim = new int[]{3, 4}; Object objArr = Array.newInstance(c, dim); for(int i = 0; i < 3; i++) { Object row = Array.get(objArr, i); for(int j = 0; j < 4; j++) { Array.set(row, j, "" + (i+1)*(j+1)); } } for(int i = 0; i < 3; i++) { Object row = Array.get(objArr, i); for(int j = 0; j < 4; j++) { System.out.print(Array.get(row, j) + " "); } System.out.println(); } } }如果要得知数组元素的类型,可以在取得数组的Class实例之后,使用Class实例的getComponentType()方法,所取回的是元素的Class实例。例如:
int[] iArr = new int[5]; System.out.println(iArr.getClass().getComponentType());3. Proxy类:
java.lang.reflect.Proxy类,可协助实现动态代理功能。例如:假设打算开发一个HelloSpeaker类,其中有一个hello()方法,想要在这个hello()调用前后加上记录的功能,但又不想将记录的功能写到HelloSpeaker类中。这时可以使用Proxy类来实现动态代理。
要实现动态代理,首先要定义所要代理的接口。如下定义了有hello()方法的IHello接口。
package ysu.hxy; public interface IHello { public void hello(String name); }HelloSpeaker类实现了IHello接口,如下:
package ysu.hxy; public class HelloSpeaker implements IHello { public void hello(String name) { System.out.println("Hello," + name); } }可以实现一个处理记录的处理器(Handler),让处理器在调用hello()方法的前后进行记录的动作。一个处理器必须实现java.lang.reflect.InvocationHandler接口,InvocationHandler有一个invoke()方法必须实现。
package ysu.hxy; import java.util.logging.*; import java.lang.reflect.*; public class LogHandler implements InvocationHandler { private Logger logger = Logger.getLogger(this.getClass().getName()); private Object delegate; //绑定要代理的对象 public Object bind(Object delegate) { this.delegate = delegate; //建立并返回代理对象 return Proxy.newProxyInstance( delegate.getClass().getClassLoader(), //要被代理的接口 delegate.getClass().getInterfaces(), this); } //代理要调用的方法,并在其前后增加行为 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; try { logger.log(Level.INFO,"method starts..." + method.getName()); result = method.invoke(delegate,args); logger.log(Level.INFO,"method endss..." + method.getName()); } catch(Exception e) { logger.log(Level.INFO,e.toString()); } return result; } }主要的概念是使用Proxy.newProxyInstance()方法建立一个代理对象,建立代理对象时必须告知所要代理的操作接口,然后可以操作所建立的代理对象,在每次操作时会调用InvocationHandler的invoke()方法,invoke()方法会传入被代理对象的方法名称与运行变量,实际上要运行的方法交由method.invoke()。在method.invoke()前后加上记录动作,method.invoke()返回的对象是实际方法运行后的回传结果。先来看看一个运行的例子:
package ysu.hxy; public class ProxyDemo { public static void main(String[] args) { LogHandler handler = new LogHandler(); IHello speaker = new HelloSpeaker(); //代理speaker的对象 IHello speakerProxy = (IHello)handler.bind(speaker); speakerProxy.hello("Justin"); } }运行结果:
D:\hxy>java ysu.hxy.ProxyDemo2009-4-6 19:06:24 ysu.hxy.LogHandler invoke信息: method starts...helloHello,Justin2009-4-6 19:06:24 ysu.hxy.LogHandler invoke信息: method endss...hello
通过代理机制,在不将记录动作写入HelloSpeaker类程序代码的情况下,可以为其加入记录的功能。这只是在hello()方法前后由代理对象speakerProxy先执行记录功能而已,真正运行hello()方法时才使用speaker对象。