首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java集合包装器破坏反射的解决方法

问Java集合包装器破坏反射的解决方法
EN

Stack Overflow用户
提问于 2009-09-17 01:02:48
回答 4查看 1.9K关注 0票数 5

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

下面是一个简单的例子:

代码语言:javascript
复制
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"),第二次调用的结果是:

代码语言:javascript
复制
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中有一个线程安全的列表实现,但该实现似乎比使用Collections.synchronizedList()慢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-09-17 01:34:05

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

代码语言:javascript
复制
list.getClass()

在队伍中

代码语言:javascript
复制
System.out.println("size = " + list.getClass().getMethod("size").invoke(list));

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

绕过此异常的最好方法是在更合适的类/接口上调用size方法-通常这恰好是实现类(因为它肯定会包含方法声明或定义),但在本例中,我们需要在公共类型上调用size(),因为obj.getClass()返回了一个非公共类型。具体地说,我们需要在java.util.Collection (超级)接口或java.util.List接口上调用size()。

以下语句将在控制台中打印出"size = 1“:

代码语言:javascript
复制
System.out.println("size = " + Collection.class.getMethod("size").invoke(list));
System.out.println("size = " + List.class.getMethod("size").invoke(list));

更新

如果您想知道通过反射调用的size()方法是否同步,答案是肯定的,它是同步的。尽管调用了超类型集合/列表上的size()方法,但SynchronizedCollection内部类中的size()方法仍会被调用,而且这恰好是同步的。这只是一个实现细节,因为集合是包装的,所以保证可以工作。

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

票数 6
EN

Stack Overflow用户

发布于 2009-09-17 01:31:01

从Collection.class获取方法(更常见的是迭代超类(和接口)以查找公共内容)。或者干脆不要使用反射。

票数 3
EN

Stack Overflow用户

发布于 2009-09-17 01:35:51

java.util.Collections$SynchronizedCollection是非公共类。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1436247

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档