怎么找到真正的public方法

发布时间:2021-11-30 17:42:43 作者:小新
来源:亿速云 阅读:377

小编给大家分享一下怎么找到真正的public方法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

摘要Class.getMethods() 能返回 class 及父类中所有 public方法。然而,这些方法并不一定能被调用,比如在 private inner class 或 lambda 表达式中声明的方法。这篇文章会介绍如何找到所有真正的 public 方法。

昨天,我试图找出某个未知对象的所有 public 方法。这件事应该很容易,用getClass()import java.lang.reflect.*;
import java.util.*;
public class ReflectionPuzzle {
 public static void main(String... args) {
   Collection<String> names = new ArrayList<>();
   Collections.addAll(names, "Goetz", "Marks", "Rose");
   printSize(names);
   printSize(Arrays.asList("Goetz", "Marks", "Rose"));
   printSize(List.of("Goetz", "Marks", "Rose"));
   printSize(Collections.unmodifiableCollection(names));
 }
 private static void printSize(Collection<?> col) {
   System.out.println("Size of " + col.getClass().getName());
   try {
     Method sizeMethod = col.getClass().getMethod("size");
     System.out.println(sizeMethod.invoke(col));
   } catch (ReflectiveOperationException e) {
     System.err.println(e);
   }
 }
}

上面的程序运行结果如下:

Size of java.util.ArrayList
3
Size of java.util.Arrays$ArrayList
java.lang.IllegalAccessException: class ReflectionPuzzle cannot
access a member of class java.util.Arrays$ArrayList (in module
java.base) with modifiers "public"
Size of java.util.ImmutableCollections$ListN
java.lang.IllegalAccessException: class ReflectionPuzzle cannot
access a member of class java.util.ImmutableCollections$ListN (in
module java.base) with modifiers "public"
Size of java.util.Collections$UnmodifiableCollection
java.lang.IllegalAccessException: class ReflectionPuzzle cannot
access a member of class
java.util.Collections$UnmodifiableCollection (in module
java.base) with modifiers "public"

只有ArrayList执行printSize()时能得到结果。虽然package problem;
public interface A {
 CharSequence foo();
}
package problem;
public interface B {
 java.io.Serializable foo();
}

接下来,我们在另一个 packagepackage problem.inner;
import problem.*;
public class Hidden {
 public static A getPrivateInnerClass() {
   return new C();
 }
 private static class C implements A, B {
   public String foo() {
     return "Hello World";
   }
   public String bar() {
     return "Should not be visible";
   }
 }
 public static A getMethodClass() {
   class D implements A {
     public CharSequence foo() {
       return "inside method";
     }
   }
   return new D();
 }
 public static A getLambda() {
   return () -> "Hello Lambert";
 }
}

下面这个示例展示了如何用普通的反射调用import problem.*;
import problem.inner.*;

import java.lang.reflect.*;
import java.util.stream.*;
public class TestPlainReflection {
 public static void main(String... args) {
   System.out.println("Testing private inner class");
   test(Hidden.getPrivateInnerClass());
   System.out.println();
   System.out.println("Testing method inner class");
   test(Hidden.getMethodClass());
   System.out.println();
   System.out.println("Testing lambda");
   test(Hidden.getLambda());
 }
 private static void test(A a) {
   Stream.of(a.getClass().getMethods())
       .forEach(System.out::println);
   printMethodResult(a, "foo");
   printMethodResult(a, "bar");
 }
 private static void printMethodResult(Object o, String name) {
   try {
     Method method = o.getClass().getMethod(name);
     System.out.println(method.invoke(o));
   } catch (NoSuchMethodException e) {
     System.out.println("Method " + name + "() not found");
   } catch (IllegalAccessException e) {
     System.out.println("Illegal to call " + name + "()");
   } catch (InvocationTargetException e) {
     throw new IllegalStateException(e.getCause());
   }
 }
}

结果同样不理想。通过Testing private inner class
public CharSequence problem.inner.Hidden$C.foo()
public java.io.Serializable problem.inner.Hidden$C.foo()
public String problem.inner.Hidden$C.foo()
public String problem.inner.Hidden$C.bar()
public Class Object.getClass()
public boolean Object.equals(Object)
public int Object.hashCode()
public String Object.toString()
public void Object.wait() throws InterruptedException
public void Object.wait(long) throws InterruptedException
public void Object.wait(long,int) throws InterruptedException
public void Object.notify()
public void Object.notifyAll()
Illegal to call foo()
Illegal to call bar()
Testing method inner class
public CharSequence problem.inner.Hidden$1D.foo()
public Class Object.getClass()
public boolean Object.equals(Object)
public int Object.hashCode()
public String Object.toString()
public void Object.wait() throws InterruptedException
public void Object.wait(long) throws InterruptedException
public void Object.wait(long,int) throws InterruptedException
public void Object.notify()
public void Object.notifyAll()
Illegal to call foo()
Method bar() not found
Testing lambda
public CharSequence problem.inner.Hidden$$Lambda$23/0x67840.foo()
public Class Object.getClass()
public boolean Object.equals(Object)
public int Object.hashCode()
public String Object.toString()
public void Object.wait() throws InterruptedException
public void Object.wait(long) throws InterruptedException
public void Object.wait(long,int) throws InterruptedException
public void Object.notify()
public void Object.notifyAll()
Illegal to call foo()
Method bar() not found

注意:我们无法通过这些对象调用import java.lang.reflect.*;
import java.util.*;
import java.util.stream.*;
public class Reflections {
 public static Optional<Method> getTrulyPublicMethod(
     Class<?> clazz, String name, Class<?>... paramTypes) {
   return getTrulyPublicMethods(clazz)
       .stream()
       .filter(method -> matches(method, name, paramTypes))
       .reduce((m1, m2) -> {
         Class<?> r1 = m1.getReturnType();
         Class<?> r2 = m2.getReturnType();
         return r1 != r2 && r1.isAssignableFrom(r2) ? m2 : m1;
       });
 }
 public static Collection<Method> getTrulyPublicMethods(
     Class<?> clazz) {
   Map<String, Method> result = new HashMap<>();
   findTrulyPublicMethods(clazz, result);
   return List.copyOf(result.values());
 }
 private static void findTrulyPublicMethods(
     Class<?> clazz, Map<String, Method> result) {
   if (clazz == null) return;
   Method[] methods = clazz.getMethods();
   for (Method method : methods) {
     if (isTrulyPublic(method))
       result.putIfAbsent(toString(method), method);
   }
   for (Class<?> intf : clazz.getInterfaces()) {
     findTrulyPublicMethods(intf, result);
   }
   findTrulyPublicMethods(clazz.getSuperclass(), result);
 }
 private static boolean isTrulyPublic(Method method) {
   return Modifier.isPublic(method.getModifiers()
       & method.getDeclaringClass().getModifiers());
 }
 private static String toString(Method method) {
   String prefix = method.getReturnType().getCanonicalName() +
       method.getName() + " (";
   return Stream.of(method.getParameterTypes())
       .map(Class::getCanonicalName)
       .collect(Collectors.joining(", ",
           prefix, ")"));
 }
 private static boolean matches(
     Method method, String name, Class<?>... paramTypes) {
   return method.getName().equals(name)
       && Arrays.equals(method.getParameterTypes(), paramTypes);
 }
}

可以确定的是,这里没有考虑所有返回类型和一些可能出错的 class 层次结构。但是,这段代码的确通过了我的测试。另外,使用 Optional 要比捕捉异常好。下面是 TestTrulyPublic 实现: 

import problem.*;
import problem.inner.*;
import java.lang.reflect.*;
import java.util.*;
public class TestTrulyPublic {
 public static void main(String... args) throws Exception {
   System.out.println("Testing private inner class");
   test(Hidden.getPrivateInnerClass());
   System.out.println();
   System.out.println("Testing method inner class");
   test(Hidden.getMethodClass());
   System.out.println();
   System.out.println("Testing lambda");
   test(Hidden.getLambda());
 }
 private static void test(A a) {
   Reflections.getTrulyPublicMethods(a.getClass()).forEach(
       System.out::println);
   printMethodResult(a, "foo");
   printMethodResult(a, "bar");
 }
 private static void printMethodResult(
     Object o, String methodName) {
   Optional<Method> method = Reflections.getTrulyPublicMethod(
       o.getClass(), methodName);
   method.map(m -> {
     try {
       System.out.println("m = " + m);
       return m.invoke(o);
     } catch (IllegalAccessException e) {
       throw new IllegalStateException(e);
     } catch (InvocationTargetException e) {
       throw new IllegalStateException(e.getCause());
     }
   }).ifPresentOrElse(System.out::println,
       () -> System.out.println("Method " +
           methodName + "() not found"));
 }
}

运行第二个测试,得到以下输出结果:

Testing private inner classpublic abstract java.io.Serializable problem.B.foo()
public abstract CharSequence problem.A.foo()
public Class Object.getClass()
public boolean Object.equals(Object)
publicint Object.hashCode()
public String Object.toString()
publicvoid Object.wait() throws InterruptedException
publicvoid Object.wait(long) throws InterruptedException
publicvoid Object.wait(long,int) throws InterruptedException
publicvoid Object.notify()
publicvoid Object.notifyAll()
m = public abstract java.io.Serializable problem.B.foo()
Hello World
Method bar() not found
Testing method inner classpublic abstract CharSequence problem.A.foo()
public Class Object.getClass()
public boolean Object.equals(Object)
publicint Object.hashCode()
public String Object.toString()
publicvoid Object.wait() throws InterruptedException
publicvoid Object.wait(long) throws InterruptedException
publicvoid Object.wait(long,int) throws InterruptedException
publicvoid Object.notify()
publicvoid Object.notifyAll()
m = public abstract CharSequence problem.A.foo()
inside methodfunction(){   //外汇跟单www.gendan5.comMethod bar() not found
Testing lambda
public abstract CharSequence problem.A.foo()
public Class Object.getClass()
public boolean Object.equals(Object)
publicint Object.hashCode()
public String Object.toString()
publicvoid Object.wait() throws InterruptedException
publicvoid Object.wait(long) throws InterruptedException
publicvoid Object.wait(long,int) throws InterruptedException
publicvoid Object.notify()
publicvoid Object.notifyAll()
m = public abstract CharSequence problem.A.foo()
Hello Lambert
Method bar() not found

可以看到,现在所有 foo() 调用都成功了,还可以看到这里没有找到 bar() 方法。 

以上是“怎么找到真正的public方法”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. 如何真正理解 if name 的作用
  2. 类的真正形态(十三)

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

public

上一篇:在B/S下如何保持RTF域格式

下一篇:C/C++ Qt TreeWidget单层树形组件怎么应用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》