java - Java Collections 包装器破坏反射的解决方法

标签 java reflection

今天,我发现使用 Collections.synchronizedXXX 并不能很好地配合反射。

这是一个简单的例子:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Weird{
  public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("Hello World");

    List<String> wrappedList = Collections.synchronizedList(list);

    printSizeUsingReflection(list);
    printSizeUsingReflection(wrappedList);
  }

  private static void printSizeUsingReflection(List<String> list) {
    try {
      System.out.println(
          "size = " + list.getClass().getMethod("size").invoke(list));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

第一次调用 printSizeUsingReflection 打印大小(即“1”),第二次调用结果:

java.lang.IllegalAccessException: Class Weird can not access a member of class
    java.util.Collections$SynchronizedCollection with modifiers "public"
  at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
  at java.lang.reflect.Method.invoke(Method.java:588)
  at Weird.printSizeUsingReflection(Weird.java:18)
  at Weird.main(Weird.java:13)

这有点令人惊讶和恼火。有好的解决方法吗?我知道 java.util.concurrent 中有一个线程安全的 List 实现,但该实现似乎比使用 Collections.synchronizedList() 慢。

最佳答案

异常抛出的原因是调用得到的类

list.getClass()

行内

System.out.println("size = " + list.getClass().getMethod("size").invoke(list));

返回实际类型 - java.util.Collections$SynchronizedCollection。 SynchronizedCollection 类恰好是 Collections 类的内部类,您无法访问它,因此出现异常。

绕过此异常的最佳方法是在更合适的类/接口(interface)上调用 size 方法——通常这恰好是实现类(因为它肯定包含方法声明或定义),但在我们的例子中我们鉴于 obj.getClass() 已返回非公共(public)类型,需要在公共(public)类型上调用 size()。具体来说,我们需要在 java.util.Collection(超)接口(interface)或 java.util.List 接口(interface)上调用 size()。

下面的语句会在控制台打印出“size = 1”:

System.out.println("size = " + Collection.class.getMethod("size").invoke(list));
System.out.println("size = " + List.class.getMethod("size").invoke(list));

更新

如果您想知道通过反射调用的 size() 方法是否同步,答案是肯定的,它是同步的。尽管在父类(super class)型 Collection/List 上调用了 size() 方法,但 SynchronizedCollection 内部类中的 size() 方法被调用,并且这恰好是同步的。不过,这是一个实现细节,保证可以工作,因为集合已包装。

此外,在the supertype - the Collection interface contains the size() method 时使用反射不是一个好主意。 .

关于java - Java Collections 包装器破坏反射的解决方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1436247/

相关文章:

java - 这个灰色三角形箭头在 IntelliJ 中意味着什么?

java - Spring MVC @SessionAttributes 困惑!

java - Java 中的泛型和反射

C# 反射属性顺序

java - 如何使用反射创建具有私有(private)字段和构造函数的类对象?

c# - Linq WHERE EF.Functions.Like - 为什么直接属性有效而反射无效?

Scala flatMap 通过 getConstructors 方法(反射)

java - java内存不足异常

java - 在此服务器上找不到请求的 URL/REST/WebService/MyMethod

java - JAVA中的static Initializer是闭包吗