是否可以在Java中动态生成变量名称?

时间:2009-07-28 07:59:58

标签: java dynamic code-generation names

假设我需要生成变量以保存用户的一些输入(我不知道它们有多少)。如果不使用ArrayArrayList(以及其他类型的列表和地图),我的代码可以使用(String,{{ 1}},String var001等)?如果是,请提供示例代码。

10 个答案:

答案 0 :(得分:5)

如果确实想要做类似的事情,你可以使用ASM或其他一些库来生成字节码。

以下代码将生成一个名为“foo.bar.ClassWithFields”的类,其中包含字段“var0”到“var99”。当然除了反射之外没有办法访问这些字段,因为它们在编译时不存在,而Java是一种静态类型语言。

import org.objectweb.asm.*;
import static org.objectweb.asm.Opcodes.*;

import java.lang.reflect.Field;

public class GeneratedFieldsExperiment {

    public static byte[] generateClassWithFields(int fieldCount) throws Exception {
        ClassWriter cw = new ClassWriter(0);
        FieldVisitor fv;
        MethodVisitor mv;
        AnnotationVisitor av0;

        cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "foo/bar/ClassWithFields", null, "java/lang/Object", null);

        for (int i = 0; i < fieldCount; i++) {
            fv = cw.visitField(ACC_PUBLIC, "var" + i, "Ljava/lang/String;", null, null);
            fv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(RETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        cw.visitEnd();

        return cw.toByteArray();
    }

    public static void main(String[] args) throws Exception {
        MyClassLoader loader = new MyClassLoader();
        Class<?> c = loader.defineClass("foo.bar.ClassWithFields", generateClassWithFields(100));

        System.out.println(c);
        System.out.println("Fields:");
        for (Field field : c.getFields()) {
            System.out.println(field);
        }
    }

    private static class MyClassLoader extends ClassLoader {
        public Class<?> defineClass(String name, byte[] b) {
            return defineClass(name, b, 0, b.length);
        }
    }
}

答案 1 :(得分:4)

  

不使用Array,ArrayList(和   其他类型的列表和地图)

使用这些名称创建文件。希望这对你的教授有用。

或者使用前面提到的Java Scripting API:

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");

engine.put("x", "hello"); // you can add any variable here
// print global variable "x"
engine.eval("println(x);");
// the above line prints "hello"

修改

似乎在内部这将使用Maps :)与Properties文件,Preferences API或DOM Trees(它们使用Vectors)相同。因此,如果您的教授如此挑剔,请使用文件。

答案 2 :(得分:3)

我还没有看到这个回答,所以我会去做。编写一个只写出Java源代码的程序。其中大多数可能是一个模板,你只需要一个循环,可以根据需要编写尽可能多的“字符串UserString003”类型变量。

是的,这太可怕了。但是,正如你所说,这对于家庭作业来说是一个概念上的挑战问题,因此只要没有人将其误认为“好”代码,它就可以解决问题。

答案 3 :(得分:2)

您的意思是要生成名为

的变量

var0,var1,var2并在您的代码中使用它们。

使用时有什么区别 var [0],var [1],var [2],.....

<强> BUT

您可以在运行时动态生成Java类,该类实现您在普通代码中使用的接口。然后使用编译器(例如Janino)编译此类,然后在运行时加载该类。比你动态创建一个类。

但是我想知道,这是否对你的用例来说是必要的。

修改

我现在不知道你使用这个参数的用例,但你可以在Java中使用动态参数,如example from here

// calculate average
        public static double average( double... numbers )
        {
           double total = 0.0; // initialize total

          // calculate total using the enhanced for statement
          for ( double d : numbers )              
             total += d;                          

          return total / numbers.length;
       } // end method average

答案 4 :(得分:2)

这样的命名变量看起来很像1980-ish。意思是面向对象的编程。 所以,如果你曾经为了生活而建造软件 - 请不要这样做。

但是因为它似乎是家庭作业......

当我们谈论Java中的命名变量时,我们的意思是编译的东西。与某些脚本语言不同,在Java中没有简单的方法。

因此,要么使用像Markus Lausberg所建议的运行时编译类 或者你作弊并使用Java Scripting API并使用脚本语言。这样,您就可以在运行时创建代码(在String中)。

答案 5 :(得分:2)

我认为您可以在运行时生成Java类,也可以使用像Beanshell这样的脚本引擎生成变量,甚至可以通过字节码构建类。但是我看不出你将如何在代码中使用这些变量,你还必须创建代码来处理这些变量,或者使用反射...

一个天真的解决方案:
创建一个包含var000到var999的所有变量的类,每个变量都有一个getter ......但这不是真正动态的!

答案 6 :(得分:2)

看起来你的教授对PHP有偏见(Variable variables),所以他在想是否可以在java中使用。

我个人并不认为这是可能的,而不是你提出的方式。可以做的是在运行时生成类,使用Javassist之类的工具来创建更强大的反射机制。因此,您可以在运行时创建一个包含所需变量的类(string1,string2等)。

但是,不要忘记Variable variables是一种非常糟糕的技术,这会导致代码错误。它可能在极少数情况下有用,但我真的不推荐它。

答案 7 :(得分:2)

以下是我实施并帮助我轻松修复解决方案的方式,没有太多障碍。

//创建数组列表

List accountList = new ArrayList(); 




for(int k=0;k < counter;k++){
        accountList.add(k, (String)flowCtx.getValueAt("transitId"+m));
}

迭代循环并使用索引将对象添加到arraylist中。

//在索引的帮助下在运行时检索对象

String a = accountList.get(i));

答案 8 :(得分:1)

这是不可能的,但这是使用其中一个java集合的完美候选。

使用动态分配的数组:

String[] arr = new String[RUNTIME_SIZE];

或者可以在运行时更改其大小的列表:

List list = new ArrayList<String>();

答案 9 :(得分:0)

我不知道我是否正确理解了您,但是如果您要为变量使用动态创建的名称,那么肯定可以-我正在这样做:

// rndRng() creates random numbers in specified range
// this would output dynamically created variable like "name89"
String myDynamicalyCreatedName = "name" + Utils.rndRng(0, 100);
final UberShader $myDynamicalyCreatedName = new UberShader();

如您所见,这里的关键点是符号“ $”,它基本上表示“从该符号后给出的字符串中创建变量名”,基本上就是这样-几年来对我来说就像一个魅力现在...希望这就是您想要的,它可以帮助您解决问题。