Java 在父/子类加载器之间访问包私有元素
在Java应用程序中,我声明了两个类,一个类(Java 在父/子类加载器之间访问包私有元素,java,classloader,Java,Classloader,在Java应用程序中,我声明了两个类,一个类(one)在类加载器a中声明,另一个类(two)在类加载器B中声明。类加载器a是B的父类。这两个类都有相同的包(即:org.test) 我似乎无法从Two事件访问One的包私有方法或变量。虽然A是B的父类加载器,但我得到了IllegalAccessError异常。我知道包私有可访问性是基于包名和类加载器的 是否有方法重新关联One和Two,以便Two可以访问One的包私有元素 下面是一个测试来证明这一点: package org.test; publ
one
)在类加载器a中声明,另一个类(two
)在类加载器B中声明。类加载器a是B的父类。这两个类都有相同的包(即:org.test
)
我似乎无法从Two
事件访问One
的包私有方法或变量。虽然A是B的父类加载器,但我得到了IllegalAccessError
异常。我知道包私有可访问性是基于包名和类加载器的
是否有方法重新关联One
和Two
,以便Two
可以访问One
的包私有元素
下面是一个测试来证明这一点:
package org.test;
public class ClassLoaderTest {
@Test
public void testLoading() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
One one = new One();
one.value = "test";
MemoryClassLoader classLoader = new MemoryClassLoader();
String name = one.getClass().getPackage().getName() + ".Two";
classLoader.add(name,
"package org.test;\n" +
"\n" +
"public class Two{\n" +
" public static String getValue(One one){\n" +
" return one.value;\n" +
" }\n" +
"}");
Class<?> twoClass = classLoader.loadClass(name);
assertEquals("test", twoClass.getMethod("getValue", One.class).invoke(null, one));
}
}
public class One{
String value;
}
package-org.test;
公共类类装入器测试{
@试验
public void testload()抛出ClassNotFoundException、IllegaAccessException、InstanceionException、NoSuchMethodException、InvocationTargetException{
一个=新的();
1.value=“测试”;
MemoryClassLoader classLoader=新的MemoryClassLoader();
字符串名称=一个.getClass().getPackage().getName()+“.Two”;
添加(名称,
“包组织测试;\n”+
“\n”+
“公共类二{\n”+
“公共静态字符串getValue(一个){\n”+
“返回一个。值;\n”+
“}\n”+
"}");
Class twoClass=classLoader.loadClass(名称);
assertEquals(“test”,twoClass.getMethod(“getValue”,One.class).invoke(null,One));
}
}
公共一级{
字符串值;
}
可以找到MemoryClassLoader
哪些错误与:
testLoading(org.test.ClassLoaderTest) Time elapsed: 0.214 sec <<< ERROR!
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.test.ClassLoaderTest.testLoading(ClassLoaderTest.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
....
Caused by: java.lang.IllegalAccessError: tried to access field org.test.One.value from class org.test.Two
at org.test.Two.getValue(Two.java:5)
... 34 more
testLoading(org.test.ClassLoaderTest)经过的时间:0.214秒这是预期的,因为Java中任何元素的限定定义都是从类加载器开始的,然后是它们的包。也就是说,它在编译时不会给您任何错误,但由于运行时包不同,将导致访问冲突,从而生成异常
这篇文章可能会帮助您进一步了解这一问题:
尽管如此,您仍然可以通过反射来访问这些方法,在方法调用之前调用Method.setAccessible(boolean)
。一个解决方案是将类One
编译到类加载器中:
public class ClassLoaderTest {
@Test
public void testLoading() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
String packageName = "org.test";
MemoryClassLoader classLoader = new MemoryClassLoader();
Map<String, String> toCompile = new HashMap<String, String>();
String oneName = packageName + ".One";
toCompile.put(oneName,
"package org.test;\n" +
"\n" +
"public class One{\n" +
" String value;\n" +
" }");
String twoName = packageName + ".Two";
toCompile.put(twoName,
"package org.test;\n" +
"\n" +
"public class Two{\n" +
" public static String getValue(One one){\n" +
" return one.value;\n" +
" }\n" +
"}");
classLoader.add(toCompile);
Class<?> oneClass = classLoader.loadClass(oneName);
Object one = oneClass.newInstance();
Field valueField = oneClass.getDeclaredField("value");
valueField.setAccessible(true);
valueField.set(one, "test");
valueField.setAccessible(false);
Class<?> twoClass = classLoader.loadClass(twoName);
assertEquals("test", twoClass.getMethod("getValue", oneClass).invoke(null, one));
}
}
公共类类装入器测试{
@试验
public void testload()抛出ClassNotFoundException、IllegaAccessException、InstanceionException、NoSuchMethodException、InvocationTargetException、NoSuchFieldException{
字符串packageName=“org.test”;
MemoryClassLoader classLoader=新的MemoryClassLoader();
Map to compile=new HashMap();
字符串oneName=packageName+“.One”;
toCompile.put(oneName,
“包组织测试;\n”+
“\n”+
“公共第一类{\n”+
“字符串值;\n”+
" }");
字符串twoName=packageName+“.Two”;
toCompile.put(两个名称,
“包组织测试;\n”+
“\n”+
“公共类二{\n”+
“公共静态字符串getValue(一个){\n”+
“返回一个。值;\n”+
“}\n”+
"}");
添加(toCompile);
Class oneClass=classLoader.loadClass(oneName);
Object one=oneClass.newInstance();
Field valueField=oneClass.getDeclaredField(“值”);
valueField.setAccessible(true);
valueField.set(一个“测试”);
valueField.setAccessible(false);
Class twoClass=classLoader.loadClass(twoName);
assertEquals(“test”,twoClass.getMethod(“getValue”,oneClass).invoke(null,one));
}
}
这不是最好的解决方案,因为您必须将java源代码视为字符串
。。。我正试图做到这一点而不加思考约翰卡尔
这只是一个疯狂的想法,而且(从Java的角度来看)这肯定是一件非常错误的事情,但是:
您可以(通过JNI)将库文件(*.dll、*.so等)加载到Java进程中。然后,您可以从C/C++端访问整个Java进程空间,并调用任何现有方法
有没有办法将一和二重新关联起来,这样两个人就可以访问
一个人的包是私人的吗
简单的回答:带着反思:是;无反射:无
详细答案:Java有自己的机制来控制对包或类的访问,防止用户依赖该包或类的实现的不必要细节。如果允许访问,则被访问的实体称为可访问可访问性是一个静态属性,可以在编译时确定;它只依赖于类型和声明修饰符
从
如果成员或构造函数声明为private,则访问权限为private
当且仅当其发生在顶层主体内时才允许
类,该类包含成员或构造函数的声明。A.
只能在主体内访问私有类成员或构造函数
包含成员声明的顶级类的,或
构造器。它不是由子类继承的
因此,在JavaSE中,不使用反射API是不可能的
如果使用反射API,则可访问性的静态内省将更改为动态。类是动态加载的,绑定是动态完成的,对象实例是在需要时动态创建的。从历史上看,不太活跃的是操纵的能力
Object o = hi.getClass().getMethod("foo").invoke(hi);
Method m = o.getClass().getMethod("bar");
m.setAccessible(true);
m.invoke(o);