从HashMap的comparableClassFor方法看反射

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()

以数组的形式获取泛型参数列表
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值