📄 methodutils.java
字号:
// Shortcut: If an exact match exists, return it. try { if(methodName!=null) { m=targetClass.getMethod (methodName, argTypes); if(isStaticReference && !Modifier.isStatic(entryGetModifiers(m)) ) { throw new NoSuchMethodException (callToString (targetClass, methodName, argTypes, isStaticReference)+ " resolved to instance " + m); } return m; } else return targetClass.getConstructor (argTypes); } catch (NoSuchMethodException e) { // no-args has no alternatives! if(argTypes==null || argTypes.length==0) { throw new NoSuchMethodException (callToString (targetClass, methodName, argTypes, isStaticReference)+ " not found."); } // Else fall through. } // Well, _that_ didn't work. Time to search for the Most Specific // matching function. NOTE that conflicts are possible! // 15.11.2.1 ACCESSIBLE: We apparently need to gather from two // sources to be sure we have both instance and static methods. Object[] methods; if(methodName!=null) { methods=targetClass.getMethods(); } else { methods=targetClass.getConstructors(); } if(0==methods.length) { throw new NoSuchMethodException("No methods!"); } MoreSpecific best=new MoreSpecific(); for(int i=0;i<methods.length;++i) { Object mi=methods[i]; if ( // 15.11.2.1 ACCESSIBLE: Method is public. Modifier.isPublic(entryGetModifiers(mi)) && // 15.11.2.1 APPLICABLE: Right method name (or c'tor) (methodName==null || entryGetName(mi).equals(methodName) ) && // 15.11.2.1 APPLICABLE: Parameters match arguments areMethodConvertable(entryGetParameterTypes(mi),argTypes) ) // 15.11.2.2 MORE SPECIFIC displace less specific. best.addItem(mi); } // May throw NoSuchMethodException; we pass in info needed to // create a useful exception m=best.getMostSpecific(targetClass,methodName,argTypes,isStaticReference); // 15.11.3 APPROPRIATE: Class invocation can call only static // methods. Note that the defined order of evaluation permits a // call to be resolved to an inappropriate method and then // rejected, rather than finding the best of the appropriate // methods. // // Constructors are never static, so we don't test them. if(m==null) { throw new NoSuchMethodException (callToString(targetClass, methodName, argTypes, isStaticReference)+ " -- no signature match"); } if( methodName!=null && isStaticReference && !Modifier.isStatic(entryGetModifiers(m)) ) { throw new NoSuchMethodException (callToString(targetClass, methodName, argTypes, isStaticReference)+ " resolved to instance: "+m); } return m; } ////////////////////////////////////////////////////////////////////////// /* Class.getMethod() finds only the entry point (if any) _exactly_ matching the specified argument types. Our implmentation can decide between several imperfect matches, using the same search algorithm as the Java compiler. This version more closely resembles Class.getMethod() -- we always ask the Class for the method. It differs in testing for appropriateness before returning the method; if the query is being made via a static reference, only static methods will be found and returned. */ static public Method getMethod(Class target,String methodName, Class[] argTypes,boolean isStaticReference) throws SecurityException, NoSuchMethodException { return (Method)getEntryPoint(target,methodName,argTypes,isStaticReference); } ////////////////////////////////////////////////////////////////////////// /** * Class.getMethod() finds only the entry point (if any) _exactly_ * matching the specified argument types. Our implmentation can * decide between several imperfect matches, using the same search * algorithm as the Java compiler. * * This version emulates the compiler behavior by allowing lookup to * be performed against either a class or an instance -- classname.foo() * must be a static method call, instance.foo() can invoke either static * or instance methods. * * @param target object on which call is to be made * @param methodName name of method I'm lookin' for * @param argTypes array of argument types of method * * @return the desired method * * @exception SecurityException if security violation * @exception NoSuchMethodException if no such method */ static public Method getMethod(Object target,String methodName, Class[] argTypes) throws SecurityException, NoSuchMethodException { boolean staticRef=target instanceof Class; return getMethod( staticRef ? (Class)target : target.getClass(), methodName,argTypes,staticRef); } /** Determine whether a given type can accept assignments of another type. Note that class.isAssignable() is _not_ a complete test! (This method is not needed by getMethod() or getConstructor(), but is provided as a convenience for other users.) parm: The type given in the method's signature. arg: The type we want to pass in. Legal ASSIGNMENT CONVERSIONS (5.2) are METHOD CONVERSIONS (5.3) plus implicit narrowing of int to byte, short or char. */ static private boolean isAssignmentConvertable(Class parm,Class arg) { return (arg.equals(Integer.TYPE) && (parm.equals(Byte.TYPE) || parm.equals(Short.TYPE) || parm.equals(Character.TYPE) ) ) || isMethodConvertable(parm,arg); } /** Determine whether a given method parameter type can accept arguments of another type. parm: The type given in the method's signature. arg: The type we want to pass in. Legal METHOD CONVERSIONS (5.3) are Identity, Widening Primitive Conversion, or Widening Reference Conversion. NOTE that this is a subset of the legal ASSIGNMENT CONVERSIONS (5.2) -- in particular, we can't implicitly narrow int to byte, short or char. SPECIAL CASE: In order to permit invoking methods with literal "null" values, setting the arg Class to null will be taken as a request to match any Class type. POSSIBLE PROBLEM: This may match a primitive type, which really should not accept a null value... but I'm not sure how best to distinguish those, short of enumerating them */ static private boolean isMethodConvertable(Class parm, Class arg) { if (parm.equals(arg)) // If same class, short-circuit now! return true; // Accept any type EXCEPT primitives (which can't have null values). if (arg == null) { return !parm.isPrimitive(); } // Arrays are convertable if their elements are convertable // ????? Does this have to be done before isAssignableFrom, or // does it successfully handle arrays of primatives? while(parm.isArray()) { if(!arg.isArray()) return false; // Unequal array depth else { parm=parm.getComponentType(); arg=arg.getComponentType(); } } if(arg.isArray()) return false; // Unequal array depth // Despite its name, the 1.1.6 docs say that this function does // NOT return true for all legal ASSIGNMENT CONVERSIONS // (5.2): // "Specifically, this method tests whether the type // represented by the specified class can be converted // to the type represented by this Class object via // an identity conversion or via a widening reference // conversion." if(parm.isAssignableFrom(arg)) return true; // That leaves us the Widening Primitives case. Four possibilities: // void (can only convert to void), boolean (can only convert to boolean), // numeric (which are sequenced) and char (which inserts itself into the // numerics by promoting to int or larger) if(parm.equals(Void.TYPE) || parm.equals(Boolean.TYPE) || arg.equals(Void.TYPE) || arg.equals(Boolean.TYPE)) return false; Class[] primTypes={ Character.TYPE, Byte.TYPE, Short.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE }; int parmscore,argscore; for(parmscore=0;parmscore<primTypes.length;++parmscore) if (parm.equals(primTypes[parmscore])) break; if(parmscore>=primTypes.length) return false; // Off the end for(argscore=0;argscore<primTypes.length;++argscore) if (arg.equals(primTypes[argscore])) break; if(argscore>=primTypes.length) return false; // Off the end // OK if ordered AND NOT char-to-smaller-than-int return (argscore<parmscore && (argscore!=0 || parmscore>2) ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -