新聞中心
小編給大家分享一下怎么找到真正的public方法,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
摘要Class.getMethods() 能返回 class 及父類(lèi)中所有 public方法。然而,這些方法并不一定能被調(diào)用,比如在 private inner class 或 lambda 表達(dá)式中聲明的方法。這篇文章會(huì)介紹如何找到所有真正的 public 方法。
昨天,我試圖找出某個(gè)未知對(duì)象的所有 public 方法。這件事應(yīng)該很容易,用getClass()import java.lang.reflect.*;
import java.util.*;
public class ReflectionPuzzle {
public static void main(String... args) {
Collection
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);
}
}
}
上面的程序運(yùn)行結(jié)果如下:
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執(zhí)行printSize()時(shí)能得到結(jié)果。雖然package problem;
public interface A {
CharSequence
foo();
}
package problem;
public interface B {
java.io.Serializable
foo();
}
接下來(lái),我們?cè)诹硪粋€(gè) 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";
}
}
下面這個(gè)示例展示了如何用普通的反射調(diào)用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());
}
}
}
結(jié)果同樣不理想。通過(guò)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
注意:我們無(wú)法通過(guò)這些對(duì)象調(diào)用import java.lang.reflect.*;
import java.util.*;
import java.util.stream.*;
public class Reflections {
public static Optional
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
Class> clazz) {
Map
findTrulyPublicMethods(clazz, result);
return List.copyOf(result.values());
}
private static void findTrulyPublicMethods(
Class> clazz, Map
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);
}
}
可以確定的是,這里沒(méi)有考慮所有返回類(lèi)型和一些可能出錯(cuò)的 class 層次結(jié)構(gòu)。但是,這段代碼的確通過(guò)了我的測(cè)試。另外,使用 Optional 要比捕捉異常好。下面是 TestTrulyPublic 實(shí)現(xiàn):
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"));
}
}
運(yùn)行第二個(gè)測(cè)試,得到以下輸出結(jié)果:
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
可以看到,現(xiàn)在所有 foo() 調(diào)用都成功了,還可以看到這里沒(méi)有找到 bar() 方法。
以上是“怎么找到真正的public方法”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)-成都網(wǎng)站建設(shè)公司行業(yè)資訊頻道!
新聞標(biāo)題:怎么找到真正的public方法-創(chuàng)新互聯(lián)
分享網(wǎng)址:http://www.dlmjj.cn/article/doehih.html