HashMap的comparableClassFor方法主要是为了判断传入的Compare类是否符合
class C implements Comparable <C>,如果符合则返回C,不符合则返回null
下面通过一个例子来看看:
public class ComparableClassForStudy{
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class clazz = HashMap.class;
Method method = clazz.getDeclaredMethod("comparableClassFor", Object.class);
method.setAccessible(true);
System.out.println(method.invoke(null, new A()) +"--"+A.class);
System.out.println(method.invoke(null, new B())+"--"+B.class);
System.out.println(method.invoke(null,new C())+"--"+C.class);
}
public static class A implements Comparable<Integer>{
@Override
public int compareTo(Integer o) {
return 0;
}
}
public static class B implements Comparable<B>{
@Override
public int compareTo(B o) {
return 0;
}
}
public static class C implements Comparable<C>, Serializable,Cloneable {
@Override
public int compareTo(C o) {
return 0;
}
}
}
返回结果:
因为ComparableClass在HashMap是一个无修饰的静态方法只能在HashMap类中或者java.util包中的类能调用,所以我们不能直接访问这个方法,但是可以采取反射的操作调用。
getDeclaredMethods和getMethods的区别
首先看getDeclaredMethods的JavaDoc注释
Returns a {@code Method} object that reflects the specified declared method of the class or interface represented by this{@code Class} object including public, protected, default (package) access, and private methods, but excluding inherited methods.但是不包括继承的方法
不仅可以返回public方法,也可以返回private方法如图:
再看看getMethods的JavaDoc注释
Returns an array containing {@code Method} objects reflecting all the public methods of the class or interface represented by this {@code Class} object, including those declared by the class or interface and those inherited from superclasses and superinterfaces. 返回当前类或者接口所有的public方法,包括从父类或者父接口继承过来
包括父类的public方法如图所示:
小结:在反射当中,getDeclaredMethods方法可以获取当前类或者接口所有声明的方法,但不包括继承的方法。而getMethods方法只能获取public方法包括继承的方法。
setAccessible
当我们通过反射去调用类中的私有方法,或者去修改私有成员变量的时候其实是违背Java的访问原则,因此当我们通过反射调用的时候如果是非public方法或者非public成员变量的时候,首先回去校验是否有权限操作(invoke方法中的checkAccess)。setAccessible(true)取消了权限校验的操作
public void setAccessible(boolean flag) {
AccessibleObject.checkPermission();
if (flag) checkCanSetAccessible(Reflection.getCallerClass());
setAccessible0(flag);
}
boolean setAccessible0(boolean flag) {
this.override = flag;
return flag;
}
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz,
Modifier.isStatic(modifiers) ? null : obj.getClass(),
modifiers);
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
实际上setAccessible(true)操作只是将override属性修改,在invoke中跳过了权限检查。
但是Java并不提倡这么使用,可以从警告中看出来。
小结:setAccessible()方法并没有去修改方法或者成员的访问权限,而是通过修改override的值去跳过invoke方法中的权限校验
comparableClass中的反射操作
static Class<?> comparableClassFor(Object x) {
if (x instanceof Comparable) {
//判断对象x是否是comparable的实例
Class<?> c; Type[] ts, as; ParameterizedType p;
if ((c = x.getClass()) == String.class) // bypass checks
//获取x运行时的类
return c;
if ((ts = c.getGenericInterfaces()) != null) {
//获取类c实现的接口集包含泛型信息
for (Type t : ts) {
if ((t instanceof ParameterizedType) &&
//是否是参数化类型(实现了泛型)
((p = (ParameterizedType) t).getRawType() ==
Comparable.class)
//去掉了泛型参数部分的类型对象是否是Comparable
&&
(as = p.getActualTypeArguments()) != null
//获取参数化类型的数组,也就是泛型集合
&&
//只有泛型集合长度为1,且与运行时的类一致才返回
as.length == 1 && as[0] == c) // type arg is c
return c;
}
}
}
return null;
}
getGenericInterfaces()
返回当前类实现的接口集(带泛型信息)
三个接口instanceof ParameterizedType结果分别是
true,false,false
可见只有声明了泛型类型才是ParameterizedType的实现
getRawType()
获取声明的这个类型的类或者接口
java.lang.Comparable<com.my.method.ComparableClassForStudy$C> 这个类型的声明就是接口interface java.lang.Comparable
getActualTypeArguments()
以数组的形式获取泛型参数列表