5

在我的源代码中,javax.swing.text.DefaultCaret.Handler.insertUpdate(DocumentEvent)我发现了以下几行(从第 1685 行开始):

if (e instanceof AbstractDocument.UndoRedoDocumentEvent) {
    setDot(offset + length);
    return;
}

但是当我尝试这个时:

package javax.swing.text;

public class Foo {
    public static void main(String[] args) {
        Object o = new Object();
        if (o instanceof AbstractDocument.UndoRedoDocumentEvent) {
            System.out.println("yay");
        } else {
            System.out.println("aww");
        }
    }
}

它会给:

Exception in thread "main" java.lang.IllegalAccessError: tried to access class javax.swing.text.AbstractDocument$UndoRedoDocumentEvent from class javax.swing.text.Foo
    at javax.swing.text.Foo.main(Foo.java:6)

为什么我不能instanceof反对那个阶级,但DefaultCaret.Handler可以呢?

使用 java 版本 1.6.0_20

$ java -version
java version "1.6.0_20"
OpenJDK Runtime Environment (IcedTea6 1.9.7) (6b20-1.9.7-0ubuntu1~10.04.1)
OpenJDK Client VM (build 19.0-b09, mixed mode, sharing)

更新:

根据答案,我尝试了以下方法:

文件Foo.java

package javax.swing.text;

public class Foo {
    public static void main(String[] args) {
        Object o = new Object();
        if (o instanceof Outer.Inner) {
            System.out.println("yay");
        } else {
            System.out.println("aww");
        }
    }
}

文件Outer.java

package javax.swing.text;

public class Outer {
    class Inner {
    }
}

这工作正常并按预期打印“aww”。

请注意,这两个文件都在包中javax.swing.text。另请注意,这Foo.java已经javax.swing.text在我原来的问题中。

据我所知,包裹没有“密封”。rt.jar(包含包裹的)的清单javax.swing.text不包含“密封”。该命令Package.getPackage("javax.swing.text").isSealed()返回假。

所以我可以instance of反对我自己的内部类,但不能反对AbstractDocument.UndoRedoDocumentEvent,即使包中的其他类可以。

任何想法为什么会这样?

4

2 回答 2

3

它看起来UndoRedoDocument是受包保护的,并且DefaultCaret.HandlerUndoRedoDocument同一个包中(javax.swing.text如果我没记错的话)。

于 2011-04-09T17:55:39.337 回答
1

第一个想法是包 javax.swing.text 是密封的,并且不允许您向其中添加新类。你自己的包裹也会发生同样的情况吗?


编辑:根据我的评论:

有点晚了,但我认为一个原因可能是你的类和swing类是由不同的类加载器加载的,从不同的类加载器加载的包不被认为是同一个包,即使它们具有相同的名称。

您可以找出 或 使用哪个类加载Name.class.getClassLoader()object.getClass().getClassLoader()。打印这些。(可能swing类的ClassLoader是null,它代表引导类加载器(由VM实现,在加载ClassandClassLoader类之前创建)。您的应用程序类加载器很可能是另一个。

要使用您自己的类加载器创建类,请使用 URLClassLoader。这应该将您的应用程序的类加载器作为父类(以允许类完全相互访问),但使用另一个 URL(例如,加载不在通常类路径上的类)。

你可以这样做:

  • 将您的Outer类放在应用程序的类路径中。
  • 创建一个主类(在同一类路径中),如下所示:

    class Main {
        public static void main(String[] ignored) throws Exception {
            URL url = new URL("file:///path/to/other/dir");
            ClassLoader cl = new URLClassLoader(url, Main.class.getClassLoader());
            Class<?> testClass = cl.loadClass("package.Test");
            testClass.getMethod("test").invoke(null);
        }
    }
    
  • 在与 Outer 相同的包中创建一个像这样的测试类,但根植于主类中的 URL:

    class Test {
       public static void test() {
          Object o = new Object();
          if (o instanceof Outer.Inner) {
              System.out.println("yay");
          } else {
              System.out.println("aww");
         }
       }
    }
    

如果我的理论是正确的,这应该给出相同类型的异常。(我没试过。)

于 2011-04-09T17:56:15.670 回答