📄 methodmap.java
字号:
throw new Error();
}
private static int moreSpecific(Class[] c1, Class[] c2)
{
boolean c1MoreSpecific = false;
boolean c2MoreSpecific = false;
for(int i = 0; i < c1.length; ++i)
{
if(c1[i] != c2[i])
{
c1MoreSpecific =
c1MoreSpecific ||
isMoreSpecific(c1[i], c2[i]);
c2MoreSpecific =
c2MoreSpecific ||
isMoreSpecific(c2[i], c1[i]);
}
}
if(c1MoreSpecific)
{
if(c2MoreSpecific)
{
return INDETERMINATE;
}
return MORE_SPECIFIC;
}
if(c2MoreSpecific)
{
return LESS_SPECIFIC;
}
return INDETERMINATE;
}
/**
* Returns all methods that are applicable to actual
* parameter classes represented by this ClassString object.
*/
LinkedList getApplicables(List methods)
{
LinkedList list = new LinkedList();
for (Iterator imethod = methods.iterator(); imethod.hasNext();)
{
Object method = imethod.next();
if(isApplicable(method))
{
list.add(method);
}
}
return list;
}
/**
* Returns true if the supplied method is applicable to actual
* parameter classes represented by this ClassString object.
*
*/
private boolean isApplicable(Object method)
{
Class[] methodArgs = getParameterTypes(method);
if(methodArgs.length != classes.length)
{
return false;
}
for(int i = 0; i < classes.length; ++i)
{
if(!isMethodInvocationConvertible(methodArgs[i], classes[i]))
{
return false;
}
}
return true;
}
/**
* Determines whether a type represented by a class object is
* convertible to another type represented by a class object using a
* method invocation conversion, treating object types of primitive
* types as if they were primitive types (that is, a Boolean actual
* parameter type matches boolean primitive formal type). This behavior
* is because this method is used to determine applicable methods for
* an actual parameter list, and primitive types are represented by
* their object duals in reflective method calls.
* @param formal the formal parameter type to which the actual
* parameter type should be convertible
* @param actual the actual parameter type.
* @return true if either formal type is assignable from actual type,
* or formal is a primitive type and actual is its corresponding object
* type or an object type of a primitive type that can be converted to
* the formal type.
*/
private static boolean isMethodInvocationConvertible(Class formal, Class actual)
{
// Check for identity or widening reference conversion
if(formal.isAssignableFrom(actual))
{
return true;
}
// Check for boxing with widening primitive conversion. Note that
// actual parameters are never primitives.
if(formal.isPrimitive())
{
if(formal == Boolean.TYPE && actual == Boolean.class)
return true;
if(formal == Character.TYPE && actual == Character.class)
return true;
if(formal == Byte.TYPE && actual == Byte.class)
return true;
if(formal == Short.TYPE &&
(actual == Short.class || actual == Byte.class))
return true;
if(formal == Integer.TYPE &&
(actual == Integer.class || actual == Short.class ||
actual == Byte.class))
return true;
if(formal == Long.TYPE &&
(actual == Long.class || actual == Integer.class ||
actual == Short.class || actual == Byte.class))
return true;
if(formal == Float.TYPE &&
(actual == Float.class || actual == Long.class ||
actual == Integer.class || actual == Short.class ||
actual == Byte.class))
return true;
if(formal == Double.TYPE &&
(actual == Double.class || actual == Float.class ||
actual == Long.class || actual == Integer.class ||
actual == Short.class || actual == Byte.class))
return true;
}
// Special case for BigDecimals as we deem BigDecimal to be
// convertible to any numeric type - either object or primitive.
// This can actually cause us trouble as this is a narrowing
// conversion, not widening.
return isBigDecimalConvertible(formal, actual);
}
private String listArgumentTypes()
{
StringBuffer buf =
new StringBuffer(classes.length * 32).append('(');
for(int i = 0; i < classes.length; ++i)
{
buf.append(classes[i].getName()).append(',');
}
buf.setLength(buf.length() - 1);
return buf.append(')').toString();
}
}
/**
* Determines whether a type represented by a class object is
* convertible to another type represented by a class object using a
* method invocation conversion, without matching object and primitive
* types. This method is used to determine the more specific type when
* comparing signatures of methods.
* @return true if either formal type is assignable from actual type,
* or formal and actual are both primitive types and actual can be
* subject to widening conversion to formal.
*/
private static boolean isMoreSpecific(Class specific, Class generic)
{
// Check for identity or widening reference conversion
if(generic.isAssignableFrom(specific))
{
return true;
}
// Check for widening primitive conversion.
if(generic.isPrimitive())
{
if(generic == Short.TYPE && (specific == Byte.TYPE))
return true;
if(generic == Integer.TYPE &&
(specific == Short.TYPE || specific == Byte.TYPE))
return true;
if(generic == Long.TYPE &&
(specific == Integer.TYPE || specific == Short.TYPE ||
specific == Byte.TYPE))
return true;
if(generic == Float.TYPE &&
(specific == Long.TYPE || specific == Integer.TYPE ||
specific == Short.TYPE || specific == Byte.TYPE))
return true;
if(generic == Double.TYPE &&
(specific == Float.TYPE || specific == Long.TYPE ||
specific == Integer.TYPE || specific == Short.TYPE ||
specific == Byte.TYPE))
return true;
}
return isBigDecimalConvertible(generic, specific);
}
private static boolean isBigDecimalConvertible(Class formal, Class actual)
{
// BigDecimal
if(BIGDECIMAL_CLASS.isAssignableFrom(actual))
{
if(NUMBER_CLASS.isAssignableFrom(formal))
{
return true;
}
if(formal.isPrimitive() &&
formal != Boolean.TYPE && formal != Character.TYPE)
{
return true;
}
}
return false;
}
/**
* A comparator that sorts Class objects by a composite key
* (!clazz.isInterface(), clazz.getName()). Used to select between multiple
* most specific common types.
*/
private static final Comparator CLASS_ORDER = new Comparator() {
public int compare(Object o1, Object o2) {
Class c1 = (Class)o1;
Class c2 = (Class)o2;
if(c1.isInterface()) {
if(!c2.isInterface()) {
return 1;
}
}
else if(c2.isInterface()) {
return -1;
}
return c1.getName().compareTo(c2.getName());
}
};
private static Class getMostSpecificCommonType(Class c1, Class c2)
{
if(c1 == c2) {
return c1;
}
if(c2.isPrimitive()) {
if(c2 == Byte.TYPE) c2 = Byte.class;
else if(c2 == Short.TYPE) c2 = Short.class;
else if(c2 == Character.TYPE) c2 = Character.class;
else if(c2 == Integer.TYPE) c2 = Integer.class;
else if(c2 == Float.TYPE) c2 = Float.class;
else if(c2 == Long.TYPE) c2 = Long.class;
else if(c2 == Double.TYPE) c2 = Double.class;
}
Set a1 = getAssignables(c1, c2);
Set a2 = getAssignables(c2, c1);
a1.retainAll(a2);
if(a1.isEmpty()) {
// Can happen when at least one of the arguments is an interface, as
// they don't have Object at the root of their hierarchy
return Object.class;
}
// Gather maximally specific elements. Yes, there can be more than one
// thank to interfaces. I.e., if you call this method for String.class
// and Number.class, you'll have Comparable, Serializable, and Object as
// maximal elements.
List max = new ArrayList();
outer: for (Iterator iter = a1.iterator(); iter.hasNext();) {
Class clazz = (Class) iter.next();
for (Iterator maxiter = max.iterator(); maxiter.hasNext();) {
Class maxClazz = (Class) maxiter.next();
if(isMoreSpecific(maxClazz, clazz)) {
// It can't be maximal, if there's already a more specific
// maximal than it.
continue outer;
}
if(isMoreSpecific(clazz, maxClazz)) {
// If it's more specific than a currently maximal element,
// that currently maximal is no longer a maximal.
maxiter.remove();
}
}
// If we get here, no current maximal is more specific than the
// current class, so it is considered maximal as well
max.add(clazz);
}
if(max.size() > 1) {
// If there is more than one maximal element, choose one. We favor
// classes over interfaces. However, if all maximal elements are
// interfaces (which can happen if both original arguments to this
// method were interfaces), we choose the one that comes first
// alphabetically -- this is admittedly arbitrary, but is at least
// deterministic. It doesn't matter much as this is used for is
// creating class hints, and all this is also a rather rare corner
// case.
Collections.sort(max, CLASS_ORDER);
}
return (Class)max.get(0);
}
private static Set getAssignables(Class c1, Class c2)
{
Set s = new HashSet();
collectAssignables(c1, c2, s);
return s;
}
private static void collectAssignables(Class c1, Class c2, Set s)
{
if(c1.isAssignableFrom(c2)) {
s.add(c1);
}
Class sc = c1.getSuperclass();
if(sc != null) {
collectAssignables(sc, c2, s);
}
Class[] itf = c1.getInterfaces();
for(int i = 0; i < itf.length; ++i) {
collectAssignables(itf[i], c2, s);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -