Mar*_*rcG 19 java reflection inheritance java-8
我想获取类的所有方法,包括public,protected,package和private方法,以及包括继承的方法.
记得:
Class.getDeclaredMethods()获取public,protected,package和private方法,但不包括继承的方法.Class.getMethods获取继承的方法,但只获取公共方法.在Java 8之前,我们可以做一些事情:
Collection<Method> found = new ArrayList<Method>();
while (clazz != null) {
for (Method m1 : clazz.getDeclaredMethods()) {
boolean overridden = false;
for (Method m2 : found) {
if (m2.getName().equals(m1.getName())
&& Arrays.deepEquals(m1.getParameterTypes(), m2
.getParameterTypes())) {
overridden = true;
break;
}
}
if (!overridden) found.add(m1);
}
clazz = clazz.getSuperclass();
}
return found;
Run Code Online (Sandbox Code Playgroud)
但是现在,如果类使用默认方法实现某些接口而不被具体超类覆盖,则这些方法将逃避上述检测.此外,现在有关于具有相同名称的默认方法的规则,并且还必须考虑这些规则.
问题:获取类的所有方法的当前推荐方法是什么:
"all"的最常见定义应该是可以在类的实例方法中直接访问的方法,而不使用super或类名:
因此,当两个布尔标志都是false:时,上面的定义符合以下签名:
public Collection<Method> getAllMethods(Class clazz,
boolean includeAllPackageAndPrivateMethodsOfSuperclasses,
boolean includeOverridenAndHidden)
Run Code Online (Sandbox Code Playgroud)
理想的规范答案应该允许这些布尔标志.
Hol*_*ger 14
即使对于"之前的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()));
}
Run Code Online (Sandbox Code Playgroud)
但正如所说的,可能是它不适合你想做的任何事情.你应该首先问自己以下问题:
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()));
}
Run Code Online (Sandbox Code Playgroud)