跨不同类加载器覆盖默认访问器方法会破坏多态性

mar*_*art 7 java polymorphism inheritance classloader

在尝试使用默认访问器覆盖方法时,我遇到了一种奇怪的行为(例如:)void run().根据Java规范,如果类属于同一个包,则类可以使用或覆盖基类的默认成员.当所有类从同一个类加载器加载时,一切正常.但是如果我尝试从单独的类加载器加载子类,则多态性不起作用.

这是样本:

App.java:

import java.net.*;
import java.lang.reflect.Method;

public class App {
    public static class Base {
        void run() {
            System.out.println("error");
        }
    }
    public static class Inside extends Base {
        @Override
        void run() {
            System.out.println("ok. inside");
        }
    }
    public static void main(String[] args) throws Exception {
        {
            Base p = (Base) Class.forName(Inside.class.getName()).newInstance();
            System.out.println(p.getClass());
            p.run();
        } {
            // path to Outside.class
            URL[] url = { new URL("file:/home/mart/workspace6/test2/bin/") };
            URLClassLoader ucl = URLClassLoader.newInstance(url);
            final Base p = (Base) ucl.loadClass("Outside").newInstance();
            System.out.println(p.getClass());
            p.run();
            // try reflection
            Method m = p.getClass().getDeclaredMethod("run");
            m.setAccessible(true);
            m.invoke(p);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Outside.java:应该在单独的文件夹中.否则classloader将是相同的

public class Outside extends App.Base {
    @Override
    void run() {
        System.out.println("ok. outside");
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

class App$Inside
ok. inside
class Outside
error
ok. outside
Run Code Online (Sandbox Code Playgroud)

所以然后我打电话给Outside#run()Base#run()(输出中的"错误").思考工作正常.

怎么了?或者是预期的行为?我能以某种方式解决这个问题吗?

axt*_*avt 5

Java虚拟机规范:

5.3创建和加载
...
在运行时,类或接口不仅由其名称决定,而是由一对决定:它的完全限定名称及其定义的类加载器.每个这样的类或接口都属于单个运行时包.类或接口的运行时包由包名称和类或接口的类加载器定义.


5.4.4访问控制
... 当且仅当满足以下任一条件时,类或接口D才能访问
字段或方法R :

  • ...
  • R是或者是protected私有的(也就是既不是public也不 protectedprivate),并且由与D相同的运行时包中的类声明.