溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么找到真正的public方法

發布時間:2021-11-30 17:42:43 來源:億速云 閱讀:601 作者:小新 欄目:編程語言

小編給大家分享一下怎么找到真正的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方法”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女