如何使用javassist实例化运行时创建的类?

问题描述 投票:0回答:2

我刚刚开始使用 javassist,我似乎不知道如何实例化在运行时创建的类。

makeNewClass()
方法使
NewClass
类像这样:

public bin.objects.base.NewClass {
    public int quantity = 5;
    private float weight = 30.25f;

    public float getWeight() { return weight; }
    public void setWeight(float weight) { this.weight = weight; }
    public float totalWeight() { return quantity * getWeight(); }
}

这个方法效果很好:

public void makeNewClass() throws NotFoundException, IOException, CannotCompileException {
        // ClassMaker maker holds the CtClass object and handles all the "making"
        ClassMaker maker = new ClassMaker("bin.objects.base.NewClass");

        maker.addField(CtClass.intType, "quantity", "5", Modifier.PUBLIC);
        maker.addField(CtClass.floatType, "weight", "30.25f", Modifier.PRIVATE);

        maker.addMethod(Modifier.PUBLIC, CtClass.floatType, "totalWeight", null, null, 
                "{ return quantity * getWeight(); }", null, MethodType.standard);
        maker.getCtClass().writeFile();
    }

现在问题开始了。该方法应该实例化

NewClass
,访问其字段并调用其方法。

    public void testNewClass() 
            throws Throwable {
        CtClass ctclass =  ClassPool.getDefault().get("bin.objects.base.NewClass");
        
        Object testClass = ctclass.toClass(new Loader(), null);
        
        // Throws NoSuchFieldException
        Field q = testClass.getClass().getDeclaredField("quantity");
        int quantity = (int) q.get(testClass);

        Class[] cArg = new Class[1];
        cArg[0] = Float.class;

        // Throws NoSuchMethodException
        Method m = testClass.getClass().getDeclaredMethod("getWeight", cArg);
        float weight = (float) m.invoke(testClass, null);

        // Throws NoSuchMethodException
        m = testClass.getClass().getDeclaredMethod("totalWeight", cArg);
        float totalWeight = (float) m.invoke(testClass, null);
        
        System.out.println("quantity = " + quantity +
                "weight = " + weight +
                "totalWeight = " + totalWeight);
    }

现在,我已经发现

testClass
实际上是被初始化为
java.lang.Class
的实例,而不是
bin.objects.base.NewClass
。所以,显然,它不会找到
NewClass
的字段和方法。

问题是:我该如何解决这个问题?我尝试使用

java.lang.Class.cast()
方法,但没有成功。

java reflection javassist
2个回答
2
投票

我终于找出问题所在了。

显然,这是类加载器的问题。我在这篇文章中找到了答案。为了解决这个问题,我只添加了这一行:

Class newClasse = ctclass.toClass(this.getClass().getClassLoader(), 
    this.getClass().getProtectionDomain());

@nullpointer 的回答也有帮助。

因此,经过一些更多的更改,

testNewClass()
方法最终变成了这样:

public void testNewClass() 
            throws Throwable {
        CtClass ctclass =  ClassPool.getDefault().get("bin.objects.base.NewClass");
        Class newClass = ctclass.toClass(this.getClass().getClassLoader(), 
            this.getClass().getProtectionDomain());
        Object objNewClass  = newClass.newInstance();

        System.out.println("Accessing the field 'public int quantity'..."); 
        Field q = newClass.getDeclaredField("quantity");        
        int quantity = (int) q.get(objNewClass);
        System.out.println("quantity = " + quantity);

        System.out.println("\nAccessing the field 'private float weight' " +
            "through the method 'public float getWeight()'...");
        Method m = newClass.getDeclaredMethod("getWeight", null);
        float weight = (float) m.invoke(objNewClass, null);
        System.out.println("weight = " + weight);

        System.out.println("\nAccessing the method 'public float totalWeight()'...");
        m = newClass.getDeclaredMethod("totalWeight", null);
        float totalWeight = (float) m.invoke(objNewClass, null);        
        System.out.println("totalWeight = " + totalWeight);
    }

0
投票

尝试使用反射来获取类对象:

Field q = Class.forName("bin.objetos.base.NovaClasse").getDeclaredField("quantity");

您也可以对其他字段执行相同的操作。

© www.soinside.com 2019 - 2024. All rights reserved.