189 8069 5689

怎么找到真正的public方法

小编给大家分享一下怎么找到真正的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 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 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 getTrulyPublicMethods(
     Class clazz) {
   Map result = new HashMap<>();
   findTrulyPublicMethods(clazz, result);
   return List.copyOf(result.values());
 }
 private static void findTrulyPublicMethods(
     Class clazz, Map 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 = 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方法”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注创新互联行业资讯频道!


网站栏目:怎么找到真正的public方法
文章转载:http://cdxtjz.com/article/giidso.html

其他资讯