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

URLClassLoader和包专用方法的可访问性

龚浩宕
2023-03-14
问题内容

我有一个类Formula,位于package中javaapplication4,我使用URLClassLoader加载该类。但是,当我从Test1位于同一包中的另一个类调用它时,我无法访问具有默认访问修饰符的方法(我可以访问公共方法)。

我得到以下异常:

java.lang.IllegalAccessException:类javaapplication4.Test1无法访问带有修饰符“”的类javaapplication4.Formula的成员

如何访问在运行时从同一包中加载的类的包私有方法

我想这是使用其他类加载器的问题,但不确定为什么(我已经设置了URLClassLoader的父级)。

SSCCE重现问题(Windows路径)-我认为问题出在loadClass方法中:

public class Test1 {

    private static final Path TEMP_PATH = Paths.get("C:/temp/");

    public static void main(String[] args) throws Exception {
        String thisPackage = Test1.class.getPackage().getName();
        String className = thisPackage + ".Formula"; //javaapplication4.Formula
        String body = "package " + thisPackage + ";   "
                    + "public class Formula {         "
                    + "    double calculateFails() {  "
                    + "        return 123;            "
                    + "    }                          "
                    + "    public double calculate() {"
                    + "        return 123;            "
                    + "    }                          "
                    + "}                              ";

        compile(className, body, TEMP_PATH);
        Class<?> formulaClass = loadClass(className, TEMP_PATH);

        Method calculate = formulaClass.getDeclaredMethod("calculate");
        double value = (double) calculate.invoke(formulaClass.newInstance());
        //next line prints 123
        System.out.println("value = " + value);

        Method calculateFails = formulaClass.getDeclaredMethod("calculateFails");
        //next line throws exception:
        double valueFails = (double) calculateFails.invoke(formulaClass.newInstance());
        System.out.println("valueFails = " + valueFails);
    }

    private static Class<?> loadClass(String className, Path path) throws Exception {
        URLClassLoader loader = new URLClassLoader(new URL[]{path.toUri().toURL()}, Test1.class.getClassLoader());
        return loader.loadClass(className);
    }

    private static void compile(String className, String body, Path path) throws Exception {
        List<JavaSourceFromString> sourceCode = Arrays.asList(new JavaSourceFromString(className, body));

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        fileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(path.toFile()));
        boolean ok = compiler.getTask(null, fileManager, null, null, null, sourceCode).call();

        System.out.println("compilation ok = " + ok);
    }

    public static class JavaSourceFromString extends SimpleJavaFileObject {
        final String code;

        JavaSourceFromString(String name, String code) {
            super(URI.create("string:///" + name.replace('.', '/') + JavaFileObject.Kind.SOURCE.extension),
                    JavaFileObject.Kind.SOURCE);
            this.code = code;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
            return code;
        }
    }
}

问题答案:

运行时的类由其完全限定名称和ClassLoader标识。

例如,当您测试两个Class<T>对象是否相等时,如果它们具有相同的规范名称,但是从不同的ClassLoader加载的,则它们将不相等。

对于两个属于同一个包的类(进而能够访问包私有方法),它们也需要从同一个ClassLoader加载,在这里不是这种情况。实际上Test1是由系统类加载器加载的,而公式是由inside中创建的URLClassLoader加载的loadClass()

如果您为URLClassLoader指定一个父加载器以使其加载Test1,则仍然使用两个不同的加载器(您可以通过声明加载器是否相等来对其进行检查)。

我认为您无法使Formula该类由同一个Test1ClassLoader加载(您必须使用众所周知的路径并将其放在CLASSPATH上),但是我发现了一种相反的方法:加载Test1in的另一个实例用于加载公式的ClassLoader。这是伪代码中的布局:

class Test1 {

  public static void main(String... args) {
    loadClass(formula);
  }

  static void loadClass(location) {
    ClassLoader loader = new ClassLoader();
    Class formula = loader.load(location);
    Class test1 = loader.load(Test1);
    // ...
    Method compute = test1.getMethod("compute");
    compute.invoke(test1, formula);
  }

  static void compute(formula) {
    print formula;
  }
}

这是pastebin。一些注意事项:null为避免上面列出的问题,我为URLClassLoader
指定了一个父级,并且我操纵了字符串以实现此目的-
但不知道这种方法在其他部署方案中的稳定性如何。另外,我使用的URLCLassLoader仅在两个目录中搜索以找到类定义,而不是在CLASSPATH中列出的所有条目



 类似资料:
  • 我已经创建了一个内部私有api,希望从ec2实例访问它。为此,我创建了一个endpoint,它启用了私有dns。我已经应用了允许任何人访问的资源策略(目前用于测试)。 当我从ec2实例中点击我的api时,它给出了以下给定的错误 启用私人DNS: true 专用dns名称:*。执行api。区域亚马逊。通用域名格式 资源政策: 是的,我在更改资源策略后部署了api。 VPCendpoint的安全组(出

  • 问题内容: 如果我有一个包私有的Java类(用“ class”声明,而不是“ public class”),那么将内部方法声明为public或protected或package- private确实没有区别,对吗?那么我应该使用哪个,或者什么时候该使用呢?我有点困惑。 问题答案: 如果我有一个包私有的Java类(用“ class”声明,而不是“ public class”),那么将内部方法声明为p

  • 我使用Python通过Databricks connect访问Databricks。在墙后面,这使用了spark,它确实是基于java的,所以为了使用它,我需要java。JDK已下载(版本14),设置为JAVA\u HOME env,但在运行代码时,出现以下错误: 原因:java。lang.reflect。InaccessibleObjectException:无法生成私有java。nio。Dir

  • 我有几个用注释的公共方法,IntelliJ显示了警告,它们可以是包私有的,也可以是私有的。 既然用注释的方法应该是公共的,我如何才能在IntelliJ中仅对这些方法禁用此检查/警告?

  • 问题内容: 在下面的代码中,Consumer类可以访问Parent类的受保护方法。由于Parent和Consumer类之间没有关系,这怎么可能。 谢谢 问题答案: 表示:相同的包或通过继承。由于您的课程都在(实际上不建议使用),因此可以进行访问。顺便说一句:如果您尝试测试Java访问控制,则会忘记(= no修饰符= )。 另一方面,访问是指:从该特定类(以及仍然是主机类成员的非静态内部类)之外的任

  • 问题内容: 大家好,我刚刚开始学习Java,我想知道如何访问另一个方法中声明的数组?设计看起来像这样: } 问题答案: 了解Java变量的范围。这是我可以在Google快速搜索中找到的链接。http://www.java-made-easy.com/variable- scope.html 您可以在类级别声明数组,然后可以在所有方法中访问它。 或者,您可以在方法中传递变量。 考虑到信息量,我有一个