即使对于“在 Java 8 之前”的场景,您的代码片段也是不正确的。但是收集所有方法并不是通常的情况,因为您通常需要有关特定上下文的方法,例如,您可能想知道给定上下文可以访问哪些方法,即使您考虑非方法,也不包括所有方法。如果你真的想要所有的方法,你必须记住,方法永远不会被重写,包私有方法只有在在同一个中声明时才会被重写。因此,筛选每个遇到的方法签名是不正确的。public
private
static
package
更糟糕的是,方法可能会被不同的修饰符覆盖。后者可以通过保持从实际类开始的想法来解决,并用于获取所有方法(包括方法)并遍历超类层次结构,以便已经遇到的覆盖具有限制最少的访问修饰符。Class.getMethods()
public
default
java.lang.Object
顺便说一句,嵌套线性搜索循环从来都不是一个好主意。你很快就会得到一个二次或更糟糕的复杂性。
您可以使用以下方法收集方法:
public static Set<Method> getAllMethods(Class<?> cl) {
Set<Method> methods=new LinkedHashSet<>();
Collections.addAll(methods, cl.getMethods());
Map<Object,Set<Package>> types=new HashMap<>();
final Set<Package> pkgIndependent = Collections.emptySet();
for(Method m: methods) types.put(methodKey(m), pkgIndependent);
for(Class<?> current=cl; current!=null; current=current.getSuperclass()) {
for(Method m: current.getDeclaredMethods()) {
final int mod = m.getModifiers(),
access=Modifier.PUBLIC|Modifier.PROTECTED|Modifier.PRIVATE;
if(!Modifier.isStatic(mod)) switch(mod&access) {
case Modifier.PUBLIC: continue;
default:
Set<Package> pkg=
types.computeIfAbsent(methodKey(m), key -> new HashSet<>());
if(pkg!=pkgIndependent && pkg.add(current.getPackage())) break;
else continue;
case Modifier.PROTECTED:
if(types.putIfAbsent(methodKey(m), pkgIndependent)!=null) continue;
// otherwise fall-through
case Modifier.PRIVATE:
}
methods.add(m);
}
}
return methods;
}
private static Object methodKey(Method m) {
return Arrays.asList(m.getName(),
MethodType.methodType(m.getReturnType(), m.getParameterTypes()));
}
但如前所述,它可能不适合你想做的任何事情。您应该首先问自己以下问题:
- 您是否正在寻找构成API的方法(通常也是唯一的)?
public
protected
- 或者你想真正看到某个/上下文可以访问的方法?
class
package
- 是否应包括方法?
static
- 是否应包括合成/桥接方法?
- 等。
以下是适合您更具体要求的修订方法:
public static Collection<Method> getAllMethods(Class clazz,
boolean includeAllPackageAndPrivateMethodsOfSuperclasses,
boolean includeOverridenAndHidden) {
Predicate<Method> include = m -> !m.isBridge() && !m.isSynthetic() &&
Character.isJavaIdentifierStart(m.getName().charAt(0))
&& m.getName().chars().skip(1).allMatch(Character::isJavaIdentifierPart);
Set<Method> methods = new LinkedHashSet<>();
Collections.addAll(methods, clazz.getMethods());
methods.removeIf(include.negate());
Stream.of(clazz.getDeclaredMethods()).filter(include).forEach(methods::add);
final int access=Modifier.PUBLIC|Modifier.PROTECTED|Modifier.PRIVATE;
Package p = clazz.getPackage();
if(!includeAllPackageAndPrivateMethodsOfSuperclasses) {
int pass = includeOverridenAndHidden?
Modifier.PUBLIC|Modifier.PROTECTED: Modifier.PROTECTED;
include = include.and(m -> { int mod = m.getModifiers();
return (mod&pass)!=0
|| (mod&access)==0 && m.getDeclaringClass().getPackage()==p;
});
}
if(!includeOverridenAndHidden) {
Map<Object,Set<Package>> types = new HashMap<>();
final Set<Package> pkgIndependent = Collections.emptySet();
for(Method m: methods) {
int acc=m.getModifiers()&access;
if(acc==Modifier.PRIVATE) continue;
if(acc!=0) types.put(methodKey(m), pkgIndependent);
else types.computeIfAbsent(methodKey(m),x->new HashSet<>()).add(p);
}
include = include.and(m -> { int acc = m.getModifiers()&access;
return acc!=0? acc==Modifier.PRIVATE
|| types.putIfAbsent(methodKey(m), pkgIndependent)==null:
noPkgOverride(m, types, pkgIndependent);
});
}
for(clazz=clazz.getSuperclass(); clazz!=null; clazz=clazz.getSuperclass())
Stream.of(clazz.getDeclaredMethods()).filter(include).forEach(methods::add);
return methods;
}
static boolean noPkgOverride(
Method m, Map<Object,Set<Package>> types, Set<Package> pkgIndependent) {
Set<Package> pkg = types.computeIfAbsent(methodKey(m), key -> new HashSet<>());
return pkg!=pkgIndependent && pkg.add(m.getDeclaringClass().getPackage());
}
private static Object methodKey(Method m) {
return Arrays.asList(m.getName(),
MethodType.methodType(m.getReturnType(), m.getParameterTypes()));
}