Java 如何重用类实例化的逻辑并绕过IllegaAccessException?

Java 如何重用类实例化的逻辑并绕过IllegaAccessException?,java,lambda,reflection,Java,Lambda,Reflection,目标:创建一个包含一些反射代码的util类,特别是创建新类实例的代码。这段代码不是很简单,所以我想把它保存在一个util函数中,这样我就可以多次重用它 方法/想法:创建ClassUtil,该函数将返回创建新类实例的lambda。我将在MyClassFactory中执行该lambda,我知道该类可以创建MyClassOne的新实例,因为它将在同一个包中,并且默认构造函数是package private access修饰符,因此ClassUtil无法创建该类的实例,但因为我在一个类中执行lambda

目标:创建一个包含一些反射代码的util类,特别是创建新类实例的代码。这段代码不是很简单,所以我想把它保存在一个util函数中,这样我就可以多次重用它

方法/想法:创建ClassUtil,该函数将返回创建新类实例的lambda。我将在MyClassFactory中执行该lambda,我知道该类可以创建MyClassOne的新实例,因为它将在同一个包中,并且默认构造函数是package private access修饰符,因此ClassUtil无法创建该类的实例,但因为我在一个类中执行lambda,所以所有这些都应该是好的

错误:

java.lang.IllegalAccessException:com.util.ClassUtil类无法使用修饰符访问com.somepackage.MyClassOne类的成员

问题:如何让Java运行时认为是MyClassFactory在尝试实例化

统一建模语言:

代码:

包com.somepackage 导入com.util.ClassUtil; 公共类MyClassFactory{ 公共MyClass创建MyClass{ 字符串implClassFQN=; 返回MyClass ClassUtil.createClassInstance.applyimplClassFQN; } } 包com.util; 导入java.lang.reflect.InvocationTargetException; 导入java.util.function.function; 公共类ClassUtil{ /** *@return给定类的完全限定名,返回该类的新实例 */ 公共静态函数createClassInstance{ 返回classFQN->{ 试一试{ 返回Class.forNameclassFQN.getDeclaredConstructor.newInstance; }捕获类NotFounde异常{ 抛出未找到属性文件中指定的新RuntimeExceptionImpl类,e; }捕获无此方法异常{ 未找到抛出新RuntimeExceptionDefault构造函数,e; }捕获非法访问异常|实例化异常|调用目标异常e{ 抛出新的RuntimeExceptionOne; } }; } } 解决方法/新方法:有人知道我如何能够采取不同的方法来实现相同的目标吗


注意:如果我将ClassUtil中的代码放入MyClassFactory,它可以正常工作,但我希望它可以重用。

尝试通过以下方式设置可访问的构造函数:


尝试设置可通过以下方式访问的构造函数:


从字面上回答您的问题,假设调用方对所调用的方法有足够的信任,则有一个方法可以传递给另一个方法来执行操作,而不需要访问重写

与访问覆盖不同的是,即使在受限环境中,如安装了安全管理器,或访问将跨越模块边界时,这也可以工作。此外,类查找就像在调用方的代码中发生一样执行,这在两个包属于不同的类装入器时可能是相关的

package com.somepackage;

import com.util.ClassUtil;
import java.lang.invoke.MethodHandles;

public class MyClassFactory {
    public static void main(String[] args) {
        MyClass obj = new MyClassFactory().createMyClass();
        System.out.println("created "+obj);
    }
    public MyClass createMyClass() {
        String implClassFQN = MyClassFactory.class.getName()+"$MyClass";
        return (MyClass)ClassUtil.createClassInstance(MethodHandles.lookup())
            .apply(implClassFQN);
    }
    private static class MyClass { // normally inaccessible by com.util.ClassUtil

    }
}

从字面上回答您的问题,假设调用方对所调用的方法有足够的信任,则有一个方法可以传递给另一个方法来执行操作,而不需要访问重写

与访问覆盖不同的是,即使在受限环境中,如安装了安全管理器,或访问将跨越模块边界时,这也可以工作。此外,类查找就像在调用方的代码中发生一样执行,这在两个包属于不同的类装入器时可能是相关的

package com.somepackage;

import com.util.ClassUtil;
import java.lang.invoke.MethodHandles;

public class MyClassFactory {
    public static void main(String[] args) {
        MyClass obj = new MyClassFactory().createMyClass();
        System.out.println("created "+obj);
    }
    public MyClass createMyClass() {
        String implClassFQN = MyClassFactory.class.getName()+"$MyClass";
        return (MyClass)ClassUtil.createClassInstance(MethodHandles.lookup())
            .apply(implClassFQN);
    }
    private static class MyClass { // normally inaccessible by com.util.ClassUtil

    }
}

我太过沉迷于欺骗Java了——它认为是另一个类进行了实例化,我甚至没有想到像您的@PSandro这样的简单解决方案来忽略访问修饰符:非常感谢您这么快的回答!我太过沉迷于欺骗Java了——它认为是另一个类进行了实例化,我甚至没有想到像您的@PSandro这样的简单解决方案来忽略访问修饰符:非常感谢您这么快的回答!谢谢@Holger,MethodHandles是我以前没有见过的东西,尽管它已经存在了很长一段时间。我无法通过搜索web找到有用的资源,大多数人只是将其与reflection或lambdametafactory进行比较,并做了一些利弊分析,但没有说明何时使用哪个、什么用例最适合每个人。显然,在功能上存在重叠,因此必须为每种功能都提供一个最佳方案。我会找一本新书,等我有时间的时候再做我自己的分析。如果您有任何建议,我洗耳恭听:这解决了问题标题中的问题以及问题正文中提出的在线问题。>如何让Java运行时认为是MyClassFactory在尝试实例化?所以我接受了这个。谢谢@Holger,MethodHandles是我以前没见过的东西,尽管它已经存在了很长一段时间了。我在网上找不到有用的资源,
他们中的大多数只是将它与反射或lambdametafactory进行比较,并做一些利弊分析,但没有说明何时使用哪个,什么用例最适合每种情况。显然,在功能上存在重叠,因此必须为每种功能都提供一个最佳方案。我会找一本新书,等我有时间的时候再做我自己的分析。如果您有任何建议,我洗耳恭听:这解决了问题标题中的问题以及问题正文中提出的在线问题。>如何让Java运行时认为是MyClassFactory在尝试实例化?所以接受这个。
package com.util;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.function.Function;

public class ClassUtil {
    /**
     * @return a new instance of the class given the class fully qualified name
     */
    public static Function<String, Object>
        createClassInstance(MethodHandles.Lookup context) {

        return name -> {
            try {
                return context.findConstructor(context.findClass(name),
                    MethodType.methodType(void.class)).invoke();
            } catch(ClassNotFoundException e) {
                throw new RuntimeException(
                    "Impl class specified in properties file not found", e);
            } catch(NoSuchMethodException e) {
                throw new RuntimeException("Default constructor not found", e);
            } catch(RuntimeException | Error e) {
                throw e;
            } catch(Throwable e) {
                throw new RuntimeException(e);
            }
        };
    }
}