0

如题,定义了一个Person类有一个private方法

public Person {
    private void test();//private方法
}

使用反射来调用
先说有问题的方法

Constructor con= Person.class.getConstructor();//构造方法
Object object = con.newInstance();//生成对象
//有问题
Person.class.getDeclareMethod("test").setAccessible(true);
Person.class.getDeclareMethod("test").invoke(object);//报错不能访问
/*Person.class.getDeclareMethod("test").isAccessible()还是等于false*/

而使用下面的写法却可以

Method = Person.class.getDeclareMethod("test");
method.setAccessible(true);
method.invoke(object);//不报错,正常执行
/*method.isAccessible()是true
而Person.class.getDeclareMethod("test").isAccessible()还是等于false
*/

这是Person.class.getDeclareMethod("test")方法的问题吗,这个问题在反射调用构造函数时也会出现,他们都有一个@CallerSensitive注解,是这个原因吗?望解答。

Jeck 5
2018-12-22 提问
3 个回答
5

已采纳

每次获取方法得到不是同一个Method对象
setAccessable仅作用于得到的方法对象,也不是全局的
所以第一种写法会报错

另外,setAccessable的属性并没有被包含在MethodequalshashCode

1
@CallerSensitive
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
    if (method == null) {
        throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
    }
    return method;
}
private static Method searchMethods(Method[] methods,
                                        String name,
                                        Class<?>[] parameterTypes)
    {
        Method res = null;
        String internedName = name.intern();
        for (int i = 0; i < methods.length; i++) {
            Method m = methods[i];
            if (m.getName() == internedName
                && arrayContentsEq(parameterTypes, m.getParameterTypes())
                && (res == null
                    || res.getReturnType().isAssignableFrom(m.getReturnType())))
                res = m;
        }

        return (res == null ? res : getReflectionFactory().copyMethod(res));
    }

...
到最后,其实是:

/**
 * Package-private routine (exposed to java.lang.Class via
 * ReflectAccess) which returns a copy of this Method. The copy's
 * "root" field points to this Method.
 */
Method copy() {
    // This routine enables sharing of MethodAccessor objects
    // among Method objects which refer to the same underlying
    // method in the VM. (All of this contortion is only necessary
    // because of the "accessibility" bit in AccessibleObject,
    // which implicitly requires that new java.lang.reflect
    // objects be fabricated for each reflective call on Class
    // objects.)
    if (this.root != null)
        throw new IllegalArgumentException("Can not copy a non-root Method");
    // 注意这里,意味着每次调用都会new一个Method对象
    Method res = new Method(clazz, name, parameterTypes, returnType,
                            exceptionTypes, modifiers, slot, signature,
                            annotations, parameterAnnotations, annotationDefault);
    res.root = this;
    // Might as well eagerly propagate this if already present
    res.methodAccessor = methodAccessor;
    return res;
}
0

以前我还真没有注意到这个问题,我帮你验证了一下.

        Constructor con = People.class.getConstructor();//构造方法
        Object object = con.newInstance();//生成对象
        Method test1 = People.class.getDeclaredMethod("test");
        test1.setAccessible(true);

        Method test2 = People.class.getDeclaredMethod("test");
        
        System.out.println(test1.hashCode());//一样的hashcode
        System.out.println(test2.hashCode());//一样的hashcode

        test1.invoke(object);//正常

我能想到的解释是: test1test2 的引用不是一个,但是equals和hashcode又是一样的,让我也迷惑了.但解释应该还是我想到但那样,他们但引用是不相同的

撰写答案

推广链接