2

我有一个类被实例化为序列的一部分(一个方法遍历类的随机列表并为每个类创建 3 个实例)

我正在编写该列表中的一个类(注意:所有类都存在于同一个包中)

我无法修改任何其他类的源文件,我需要停止我自己的所有类的实例化,或者用空方法覆盖它们的构造函数。

到目前为止,我已经尝试过使用反射,并且一直在查看类加载器,但无法弄清楚如何做到这一点

我可以通过反射获得对构造函数的引用,但到目前为止无法干扰它

编辑->我的想法(动态地重新编写和重新编译目标类),代码编译但我得到一个异常,阻止新类编译

private void reWrite(String name) {//throws IOException {
    try{
    File sourceFile = new File("/temp/" + "name" + ".java");
    System.out.println("file defined");
    FileWriter writer = new FileWriter(sourceFile);
    System.out.println("filewriter defined");

    writer.write("public class "+name+" extends Creature {/n"
            + "private static int instanceCount = 0;/n" + "public "+name+"() {/n"
            + " instanceCount++;/n" + "}/n" + "public void doTurn() {}/n"
            + "public final void creatureDestroyed() {/n"
            + " instanceCount--;/n" + "}/n"
            + "public final int getInstanceCount() {/n"
            + " return instanceCount;/n" + "}/n" + "}/n");
    writer.close();
    System.out.println("written");

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);

    fileManager.setLocation(StandardLocation.CLASS_OUTPUT,
            Arrays.asList(new File("/temp")));
    // Compile the file
    compiler.getTask(
            null,
            fileManager,
            null,
            null,
            null,
            fileManager.getJavaFileObjectsFromFiles(Arrays
                    .asList(sourceFile))).call();
    System.out.println("compiled");
    fileManager.close();
    }catch(Exception e){
        System.out.println("Print");
    }
}

编辑->以下是我根据以下评论提供的代码

try {
        getW = (World.class.getDeclaredMethod("getWorld"));
        getW.setAccessible(true);
        theWorld = getW.invoke(World.class);
        getK = (Creature.class.getDeclaredMethod("die"));
        getK.setAccessible(true);
    } catch (NoSuchMethodException exc) {
        System.out.println("Method Not Found.");
    } catch (Exception e) {
        System.out.println("well shit");
    }

    try {
        f = World.class.getDeclaredField("locations");
        f.setAccessible(true);
        locations = f.get(theWorld);
        loc = (ArrayList<Creature>) locations;
    } catch (Exception e) {
        System.out.println("well poop");
    }
    if (loc.size() > 0 && !allMine) {
        for (int i = 0; i < loc.size(); i++) {
            if (loc.get(i).getClass() != Colonial.class
                    && loc.get(i).getClass() != Plant.class) {

                try {
                    getK.invoke(loc.get(i));
                } catch (Exception e) {

                }

                loc.set(i, new OpenLand());
            }
        }
    }
4

3 回答 3

1

如果允许您修改命令行,您应该尝试 java 代理。代理是一个基本上在类加载之前挂钩的类,可以修改类的字节码。为了在不成为 JVM 专家的情况下修改字节码,javassist 是一个不错的库,它允许您编写一些类似 java 的代码并在方法之前/之后注入它。
所以基本上,你需要

  1. 编写一个修改敌人类的构造函数的代理
  2. 使用该代理启动 JVM

在这里,您有一些关于代理的最少信息:
https
: //zeroturnaround.com/rebellabs/how-to-make-java-more-dynamic-with-runtime-code-generation/ 和 javassist 教程非常清楚:
http:// jboss-javassist.github.io/javassist/tutorial/tutorial.html
当然这是一个肮脏的黑客,但你要求它

于 2013-04-05T03:07:02.010 回答
1

您可以使用sun.misc.Unsafe#allocateInstance(MyClass.class) 来构造实例,而无需实际调用构造函数。有关更多信息,请参阅http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/

于 2014-10-29T13:27:48.470 回答
0

不需要“干涉”构造函数。它是固定的。你只需要调用它,Constructor<T>.newInstance(...).如果有需要设置的对象的其他属性,调用setter。如果设置器不存在,则无法执行。

于 2013-04-05T03:12:57.407 回答