java.lang.reflect.Method

package java.lang.reflect;

import sun.reflect.MethodAccessor;
import sun.reflect.Reflection;

/**
 *
 * 描述方法的类
 *
 * 注意使用反射的方式是首先通过
 * Class.getMethod(String name, Class[] parameterTypes)获得一个Method对象
 * String表示方法名,parameterTypes表示参数列表中的每个参数对应的类型,这时先获得
 * Class对象中Method对象,与实际的操作对象无关,然后调用此方法,是通过Method.(Object obj, Object[] args)
 * 这里obj指调用方法的对象,args表示每个参数对应的值
 *
 * 例子,一下两种方式的效果是一样的(当然性能不同)
 * String ost = "lqtest";
 * String nst = ost.substring(2,6);
 *
 * String ost2 = "lqtest";
 * Class[] types = {int.class, int.class};
 * Method med = String.class.getMethod("substring", types);
 * Object[] values ={new Integer(2), new Integer(6)};
 * String nst2 = (String) med.invoke(ost2, values);
 *
 * 使用反射一切都是变化的,类名,方法名,参数列表,都是变量,而不是写死的,他们
 * 在运行时才知道具体值,而不是编译期
 *
 * comment by liqiang
 *
 * @author Kenneth Russell
 * @author Nakul Saraiya
 */
public final
class Method extends AccessibleObject implements Member {
 //定义此方法的类对象
    private Class  clazz;
    private int   slot;
    //方法名,从1.4开始它变成intern的形式
    private String  name;
    //返回类型
    private Class  returnType;
    //参数列表
    private Class[]  parameterTypes;
    //异常列表
    private Class[]  exceptionTypes;
    //方法的描述符
    private int   modifiers;
    //处理方法的实际对象
    private volatile MethodAccessor methodAccessor;
    //如果当前对象是通过拷贝得到的,则root指向拷贝前的对象
    private Method              root;

    //调用对象的安全检查的缓存,保存上一个通过检查的调用对象,如果当前的调用对象
    //不是上一个调用对象则做安全检查
    private volatile Class      securityCheckTargetClassCache;

    //构造函数
    Method(Class declaringClass,
           String name,
           Class[] parameterTypes,
           Class returnType,
           Class[] checkedExceptions,
           int modifiers,
           int slot)
    {
        this.clazz = declaringClass;
        this.name = name;
        this.parameterTypes = parameterTypes;
        this.returnType = returnType;
        this.exceptionTypes = checkedExceptions;
        this.modifiers = modifiers;
        this.slot = slot;
    }

    //通过本对象的数据生成一个新对象
    Method copy() {
     //通过本对象的数据生成一个新对象
        Method res = new Method(clazz, name, parameterTypes, returnType,
                                exceptionTypes, modifiers, slot);
        //新对象的root指向原对象
        res.root = this;
        //新对象与原对象公用一个MethodAccessor
        res.methodAccessor = methodAccessor;
        return res;
    }

    //返回声明此函数的类
    public Class getDeclaringClass() {
 return clazz;
    }

    //返回方法名
    public String getName() {
 return name;
    }

    //返回描述符
    public int getModifiers() {
 return modifiers;
    }

    //取得返回类型
    public Class getReturnType() {
 return returnType;
    }

    //返回参数列表
    public Class[] getParameterTypes() {
 return copy(parameterTypes);
    }

    //返回异常列表
    public Class[] getExceptionTypes() {
 return copy(exceptionTypes);
    }

    //判断obj是否与当前方法对象相等
    public boolean equals(Object obj) {
 if (obj != null && obj instanceof Method) {//如果是方法对象
  //转型
     Method other = (Method)obj;
    
     //定义此方法的类和方法名相等
     if ((getDeclaringClass() == other.getDeclaringClass())
  && (getName() == other.getName())) {
      
  /* Avoid unnecessary cloning */
  Class[] params1 = parameterTypes;
  Class[] params2 = other.parameterTypes;
  
  //比较参数列表
  if (params1.length == params2.length) {
      for (int i = 0; i < params1.length; i++) {
   if (params1[i] != params2[i])
       return false;
      }
      return true;
  }
  
     }
 }
 return false;
    }

    //返回hashCode
    public int hashCode() {
 return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
    }

    //方法对象的字符串表示
    public String toString() {
 try {
     StringBuffer sb = new StringBuffer();
     int mod = getModifiers();
     if (mod != 0) {
     //标志符
  sb.append(Modifier.toString(mod) + " ");
     }
     //注意它这里用的是Field方法中显示类的名字,这个方法显示数组类型跟Class.getName()不同
     //添加返回类型
     sb.append(Field.getTypeName(getReturnType()) + " ");
     //添加类名
     sb.append(Field.getTypeName(getDeclaringClass()) + ".");
     //添加方法名
     sb.append(getName() + "(");   
    
     //参数列表
     Class[] params = parameterTypes; // avoid clone
     for (int j = 0; j < params.length; j++) {
  sb.append(Field.getTypeName(params[j]));
  if (j < (params.length - 1))
      sb.append(",");
     }
     sb.append(")");
    
     //异常列表
     Class[] exceptions = exceptionTypes; // avoid clone
     if (exceptions.length > 0) {
  sb.append(" throws ");
  for (int k = 0; k < exceptions.length; k++) {
      sb.append(exceptions[k].getName());
      if (k < (exceptions.length - 1))
   sb.append(",");
  }
     }
     return sb.toString();
 } catch (Exception e) {
     return "<" + e + ">";
 }
    }

    /**
     *
     * 注意使用反射的方式是首先通过
     * Class.getMethod(String name, Class[] parameterTypes)获得一个Method对象
     * String表示方法名,parameterTypes表示参数列表中的每个参数对应的类型,这时先获得
     * Class对象中Method对象,与实际的操作对象无关,然后调用此方法,是通过Method.(Object obj, Object[] args)
     * 如果调用的方法是static的则obj对象为null,如果方法没有参数,则args的长度为0或为null
     * 如果返回值是原始类型则返回它的封装类,如果返回值是void则返回null
     */
    public Object invoke(Object obj, Object[] args)
 throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException
    {
        if (!override) {
            if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
             //获得调用对象的Class对象
                Class caller = Reflection.getCallerClass(1);
               
                Class targetClass = ((obj == null || !Modifier.isProtected(modifiers))
                                     ? clazz
                                     : obj.getClass());
                //调用此操作的对象或方法调用作用的对象与缓存不同,则做安全检查
                if (securityCheckCache != caller ||
                    targetClass != securityCheckTargetClassCache) {
                    Reflection.ensureMemberAccess(caller, clazz, obj, modifiers);
                    securityCheckCache = caller;
                    //通过安全检查的调用对象,缓存它供下次调用时使用
                    securityCheckTargetClassCache = targetClass;
                }
            }
        }
       
        if (methodAccessor == null) acquireMethodAccessor();
        return methodAccessor.invoke(obj, args);
    }

    //如果此对象是由copy生成的,则对象与生成此对象的对象使用同一个MethodAccessor
    private void acquireMethodAccessor() {
        MethodAccessor tmp = null;
       
        if (root != null) tmp = root.getMethodAccessor();
        if (tmp != null) {
            methodAccessor = tmp;
            return;
        }
       
        //不是由copy得来创建MethodAccessor对象
        tmp = reflectionFactory.newMethodAccessor(this);
        setMethodAccessor(tmp);
    }

    //返回MethodAccessor对象
    MethodAccessor getMethodAccessor() {
        return methodAccessor;
    }

    //设置MethodAccessor对象
    void setMethodAccessor(MethodAccessor accessor) {
        methodAccessor = accessor;
        if (root != null) {//如果此对象是由copy的来
         //递归调用其上级
            root.setMethodAccessor(accessor);
        }
    }

    //生成一个新的Class数组并将原数组内容考到新数组中
    static Class[] copy(Class[] in) {
 int l = in.length;
 
 if (l == 0)
     return in;
 
 Class[] out = new Class[l];
 for (int i = 0; i < l; i++)
     out[i] = in[i];
 
 return out;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在您使用 JDK 8 编译程序,然后在 JDK 17 上运行时出现的错误信息是: ``` accessible:module java.base does not "opens java.lang" to unnamed module @93c2679 at java.base/java.Lang.reflect.Accessibleobject.checkCanSetAccessible(Accessibleobject.java:354) at java.base/java.lang.reflect.Accessibleobject.checkCanSetAccessible(Accessibleobject.java:297) at java.base/java.Lang.reflect.Method.checkCanSetAccessible(Method.java:199) at java.base/java.lang.reflect.Method.setAccessible(Method.java:193) at com.sun.xml.bind.v2.runtime.reflect.opt.Injector$1.run(Injector.java:150) at com.sun.xml.bind.v2.runtime.reflect.opt.Injector$1.run(Injector.java:147) at java.base/java.security.AccessController.doPrivileged(AccessController.java:318) at com.sun.xml.bind.v2.runtime.reflect.opt.Injector.<clinit>(Injector.java:146) ``` 这个错误表明在您的程序中,存在一个访问权限问题。具体来说,它指出 java.base 模块没有将 java.lang 模块开放给未命名模块,导致访问权限被拒绝。 这个问题可能是由于 JDK 17 引入了模块化系统,而 JDK 8 不支持模块化系统导致的。要解决这个问题,您可以尝试以下几个步骤: 1. 尝试将代码升级为使用模块化系统。在 JDK 9 及更高版本中,引入了模块化系统,您可以通过创建模块描述文件(module-info.java)来声明模块依赖和开放的包。请确保您的代码和依赖项都兼容模块化系统,并正确声明了访问权限。 2. 如果您无法将代码升级为使用模块化系统,您可以尝试在 JDK 17 上使用 `--illegal-access=permit` 参数来放宽对非法访问的检查。请注意,这个参数只是一个临时解决方案,并不推荐在生产环境中使用。 3. 如果您的代码依赖于特定的库或框架,可能需要升级这些库或框架以与 JDK 17 兼容。请查阅相关文档或联系库/框架的开发者以获取更多支持。 需要注意的是,尽管您的程序在 Windows 上运行没有问题,但在 Linux 上出现了错误。这可能是由于平台差异导致的,因此建议您在运行时检查和解决与平台相关的问题。 如果以上步骤都没有解决问题,建议提供更多的上下文信息,例如您的代码片段、使用的库和依赖项,以及在 Linux 上运行程序时的详细步骤,以便更好地理解和解决问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值