---------------------- android培训、java培训、期待与您交流! ----------------------
3、访问类中的字段
可以通过Class中的getFields()、getField(String name)以及getDeclaredFields()、getDeclaredField(String name)来访问类的字段。方法名中带Declared与不带Declared的含义同构造方法。假如现在想改变private类型的needCheck的值,可以用getDeclaredField(String name)方法先获取字段对象,再修改其值:
package
com.ticmy.reflect;
import
java.lang.reflect.Field;
public
class
Test {
public
static
void
main(String[] args)
throws
Exception
{
Class<?> clazz = Class.forName(
"com.ticmy.reflect.ArticleManage"
);
ArticleInterface inst = (ArticleInterface)clazz.newInstance();
Field field = clazz.getDeclaredField(
"needCheck"
);
field.setAccessible(
true
);
field.setBoolean(inst,
false
);
inst.add(
"this is a short article"
);
}
}
获取到Field对象后,通过调用其setBoolean方法修改其值。其第一个参数为想要改变字段值的对象,若是static字段,该参数可为null;如果字段为其它类型,可以调用Field类的其它setXXX方法来修改。注意到代码中有一句field.setAccessible(true),如果没有这句会报以下错误,不允许修改private变量的值,将其设置为true,就允许改变了:
Exception in thread “main” java.lang.IllegalAccessException: Class com.ticmy.reflect.Test can not access a member of class com.ticmy.reflect.ArticleManage with modifiers “private”
4、访问类中的方法
Class类中提供了getMethods()、getMethod(String name, Class… parameterTypes)以及getDeclaredMethods()、getDeclaredMethod(String name, Class… parameterTypes),其情况类似于构造方法,毋庸多言。需要说的是其带参数的方法,第一个参数是方法名,后面是对应方法的参数类型。假如这里要调用modify方法,可以先通过getMethod(String name, Class… parameterTypes)获得对应的Method对象,然后通过invoke调用:
package
com.ticmy.reflect;
import
java.lang.reflect.Method;
public
class
Test {
public
static
void
main(String[] args)
throws
Exception
{
Class<?> clazz = Class.forName(
"com.ticmy.reflect.ArticleManage"
);
ArticleInterface inst = (ArticleInterface)clazz.newInstance();
Method method = clazz.getMethod(
"modify"
,
long
.
class
,
String.
class
);
method.invoke(inst,
3
,
"this is a short article"
);
}
}
invoke的第一个参数表示调用的是哪个对象的modify方法,后面是ArticleInterface接口中modify方法按声明顺序排列的实际参数。
5、上述内容是关于反射中常用的一些方法和用法,更多功能参见java.lang.Class,java.lang.reflect.Method、java.lang.reflect.Field、java.lang.reflect.Constructor等类的JAVA API说明。
6、反射和动态代理的结合。
动态代理用于创建动态代理类,这些类不需要以java class文件的形式存在。动态代理相关的类为:java.lang.reflect.Proxy。可以通过其newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)方法创建一个代理类,其中,loader为定义代理类的类加载器,interfaces为生成的代理类要实现的接口列表,h为指派方法调用的调用处理程序。在ArticleManage示例类中,add和modify方法中都有if((!needCheck)
|| checkContent())的判断,或许还有更多方法需要这种判断,在每个方法里都写这样的判断实在是太麻烦,动态代理+方法反射调用就可以帮我们解脱痛苦:
现在将ArticleManage实现中的if判断删除:
package
com.ticmy.reflect;
import
java.util.Map;
import
java.util.Random;
import
java.util.concurrent.ConcurrentHashMap;
import
java.util.concurrent.atomic.AtomicLong;
public
class
ArticleManage
implements
ArticleInterface {
private
final
Map<Long, String> articles;
private
boolean
needCheck;
private
final
AtomicLong idIncr =
new
AtomicLong(
1
);
public
ArticleManage(
boolean
needCheck) {
System.out.println(
"带参数的构造方法"
);
this
.needCheck = needCheck;
articles =
new
ConcurrentHashMap<Long, String>();
}
public
ArticleManage() {
System.out.println(
"默认构造方法"
);
this
.needCheck =
true
;
articles =
new
ConcurrentHashMap<Long, String>();
}
public
void
del(
long
id)
throws
Exception
{
System.out.println(
"删除文章"
);
articles.remove(id);
}
public
void
add(String content)
throws
Exception
{
System.out.println(
"添加文章"
);
articles.put(idIncr.getAndIncrement(), content);
}
public
void
modify(
long
id,
String content)
throws
Exception {
System.out.println(
"修改文章内容"
);
articles.put(id, content);
}
public
boolean
checkContent()
throws
Exception
{
System.out.println(
"检查文章内容"
);
Random random =
new
Random();
int
value = random.nextInt(
100
);
if
(value <
20
) {
//20%概率失败
throw
new
Exception(
"文章内容不合法"
);
}
return
true
;
}
public
boolean
isNeedCheck() {
return
needCheck;
}
}
通过动态代理为其加上判断功能
package
com.ticmy.reflect;
import
java.lang.reflect.InvocationHandler;
import
java.lang.reflect.Method;
import
java.lang.reflect.Proxy;
public
class
Test {
public
static
void
main(String[] args)
throws
Exception
{
ArticleManage delegationObj =
new
ArticleManage();
ArticleInterface inst = (ArticleInterface)Proxy.newProxyInstance(
ArticleInterface.
class
.getClassLoader(),
new
Class[]{ArticleInterface.
class
},
new
ArticleManageInvocationHandler(delegationObj));
inst.add(
"this is a short article"
);
}
static
class
ArticleManageInvocationHandler
implements
InvocationHandler
{
private
ArticleManage delegationObj;
public
ArticleManageInvocationHandler(ArticleManage delegationObj) {
this
.delegationObj = delegationObj;
}
public
Object invoke(Object proxy, Method method, Object[] args)
throws
Exception
{
String methodName = method.getName();
Object ret =
null
;
long
start = System.currentTimeMillis();
if
(methodName.equals(
"add"
)) {
ret = method.invoke(delegationObj, args);
}
else
{
if
((!delegationObj.isNeedCheck()) || delegationObj.checkContent()) {
ret = method.invoke(delegationObj, args);
}
}
long
end = System.currentTimeMillis();
System.out.println(
"[方法调用]["
+ methodName +
"]耗时:"
+
(end - start) +
"ms"
);
return
ret;
}
}
}
看这部分
ArticleInterface inst = (ArticleInterface)Proxy.newProxyInstance(
ArticleInterface.
class
.getClassLoader(),
new
Class[]{ArticleInterface.
class
},
new
ArticleManageInvocationHandler(delegationObj));
让生成的代理类实现ArticleInterface接口,这样就可以将newProxyInstance的对象强制转换成ArticleInterface类型了。
在InvocationHandler中,可以看到其invoke方法参数中有个Method,这个Method对象是代理接口中的那些方法,例如这里将其强制转换成ArticleInterface后,假设调用了add方法,InvocationHandler中invoke方法的method就相当于ArticleInterface.class.getMethod(“add”, String.class)。
在这个例子中,当调用inst的方法时,就会自动去调用ArticleManageInvocationHandler中的invoke方法。invoke方法的第三个参数,就是调用inst中方法时传的参数。invoke方法的第一个参数即为生成的代理类对象本身,很多时候这个参数用处不大。
既然调用inst的方法时会调用这个invoke方法,那就可以在里面做一些事情了。像上面在调用实际方法之前给其加了判断,为整个方法调用计时等等,有没有种面向切面的感觉?
这是很常用的一种编程模式,如在现实中很多操作需要验证用户是否已经登录,那么就可以通过这种方式来做。
如果用了spring,可以使用spring的AOP来做,道理是类似的。
---------------------- android培训、java培训、期待与您交流! ----------------------