当前位置: 首页 > 面试题库 >

跨不同的类加载器覆盖默认访问器方法可打破多态性

方鸿羲
2023-03-14
问题内容

在尝试使用 默认访问器 (例如:)覆盖方法时,遇到一种奇怪的行为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);
        }
    }
}

outside.java:应位于单独的文件夹中。否则,类加载器将是相同的

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

输出:

class App$Inside
ok. inside
class Outside
error
ok. outside

因此,我称Outside#run()我得到了Base#run()(输出中出现“错误”)。反射正常工作。

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


问题答案:

从Java虚拟机规范:

5.3创建和加载

在运行时,类或接口的确定不仅取决于其名称,还取决于对:其完全限定的名称及其定义的类加载器。每个此类或接口都属于一个 运行时包
。类或接口的运行时包由包名称以及类或接口的定义类加载器确定。

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

  • R是protected包私有的或包私有的(即,不是publicnor
    protected也不是private),并且由与D相同的运行时包中的类声明。


 类似资料:
  • 问题内容: 我试图摆脱Java继承的束缚,并且了解到,当重写子类中的方法(和隐藏字段)时,仍然可以使用“ super”关键字从父类中访问它们。 我想知道的是,是否应将“ super”关键字用于非重写方法? 有什么区别(对于非覆盖方法/非隐藏字段)? 我在下面整理了一个例子。 和 具体来说,鉴于尚未被覆盖,应使用或?。 我想知道是否应该在访问超类的字段或方法的所有实例中使用super(以在代码中显示

  • 本文向大家介绍Android调用系统默认浏览器访问的方法,包括了Android调用系统默认浏览器访问的方法的使用技巧和注意事项,需要的朋友参考一下 一、启动android默认浏览器 这样子,android就可以调用起手机默认的浏览器访问。 二、指定相应的浏览器访问 1、指定android自带的浏览器访问 2、启动其他浏览器(当然该浏览器必须安装在机器上) 只要修改以下相应的packagename

  • 我想通过创建一个具体实现类的对象来执行接口中默认方法的定义体,该对象也覆盖了该方法。无论我是直接创建具体实现类的对象,还是通过动态绑定/多态,实现类中定义/重写的主体都只是得到执行。请看下面的代码 我想知道如何在控制台内部界面银行打印以下内容--loan()

  • 我一直在谷歌搜索和跟随不同的教程来学习如何做各种事情,到目前为止,我的进展还不错。但现在我已经停滞不前了。 我想做的是,当我的应用程序启动和用户按下登录按钮时,将它们转发到管理员主页上。 这是login.java中的代码: 非常感谢任何帮助。 附注。当用户单击该按钮时,我不只是想打开任意场景,而是想打开一个已经应用了quizapp.fxml、quizapp.css和administratorlog

  • 问题内容: 我已经能够覆盖所有名称以“ android:”为前缀的主题,但是Android themes.xml还定义了似乎无法被覆盖的属性。例如: colorTheground是在Theme.Light xml中定义的,但是在此处添加它可以使我 错误。如何为整个应用程序覆盖该样式? 问题答案: 您可以用修改属性(如)的方式覆盖标准属性,只是不要忘记添加如下前缀:

  • 问题内容: 我想覆盖Java外观。我只想显示不同的按钮。 我想要Windows Look and Feel的所有功能,但仅按钮有所不同。希望你明白我的意思。 还告诉我如何制作圆形的JtabbedPane ??? 问题答案: 自定义GUI类 调用您的自定义GUI类