简体   繁体   English

是否有可用Java动态生成变量名称的方法?

[英]Is there away to generate Variables' names dynamically in Java?

Let's say that I need to generate variables to hold some input from the user (I don't know how many they are). 假设我需要生成变量以容纳用户的一些输入(我不知道它们有多少个)。 Without using Array , ArrayList (and other kind of lists and maps) can my code generate (lets say) String variables X times with names like ( String var001 , String var002 , String var003 , etc)? 如果不使用Array ,则ArrayList (以及其他类型的列表和映射)可以在我的代码中生成(变量) String变量X次,其名称为( String var001String var002String var003等)吗? If yes, please provide sample code. 如果是,请提供示例代码。

If you really want to do something like that, you can do it through bytecode generation using ASM or some other library. 如果您确实想做类似的事情,可以使用ASM或其他一些库通过字节码生成来完成。

Here is code that will generate a class named "foo.bar.ClassWithFields" that contains fields "var0" to "var99". 这是将生成名为“ foo.bar.ClassWithFields”的类的代码,该类包含字段“ var0”至“ var99”。 Of course there is no way other than reflection to access those fields, because they don't exist at compile time and Java is a statically typed language. 当然,除了反射之外,没有其他方法可以访问这些字段,因为它们在编译时不存在,并且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);
        }
    }
}

Without using Array, ArrayList (and other kind of lists and maps) 不使用Array,ArrayList(以及其他类型的列表和映射)

Create files with these names. 用这些名称创建文件。 Hope that will work for your professor. 希望对您的教授有用。

Or use the Java Scripting API mentioned before: 或使用前面提到的Java脚本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"

EDIT 编辑

Seems like internally this will use Maps :) Same with Properties file, Preferences API, or DOM Trees (they are using Vectors). 似乎在内部,这将使用Maps :)与Properties文件,Preferences API或DOM Trees(它们正在使用Vector)相同。 So if your professor is so picky, use files. 因此,如果您的教授很挑剔,请使用文件。

I haven't seen this answered yet, so I'll go for it. 我还没有看到这个答案,所以我去解决。 Write a program that just writes out Java source code. 写一个只写出Java源代码的程序。 Most of it could be a template, and you would just have a loop that would write as many "string UserString003" type variables as you want. 其中大多数可能是模板,并且您将拥有一个循环,该循环将根据需要写入尽可能多的“ string UserString003”类型变量。

Yes, this is horrible. 是的,这太可怕了。 But, as you said, it's a conceptual challenge problem for homework, so as long as no one mistakes this for "good" code, it might solve the issue. 但是,正如您所说,这是作业的一个概念性挑战问题,因此,只要没有人将其误认为“好”代码,它就可以解决问题。

You mean you want to generate variables named 您的意思是您要生成名为

var0, var1, var2 and use them in your code. var0,var1,var2,并在您的代码中使用它们。

What is the difference when you use var[0], var[1], var[2], ..... 使用var [0],var [1],var [2],...的区别是什么。

BUT

You can generate a Java class dynamically at runtime which implements an Interface you are using in your normal code. 您可以在运行时动态生成Java类,该类实现您在常规代码中使用的接口。 Then you compile this class using a compiler (For example Janino) and then load the class at runtime. 然后,使用编译器(例如Janino)编译此类,然后在运行时加载该类。 Than you have created a class dynamically. 比您动态创建的类。

But i wonder, whether this is necessary for your usecase. 但是我想知道,这对于您的用例是否必要。

EDIT 编辑

I dont now for which usecase you are using this parameters but dynamic arguments you can use in Java like this example from here 我现在不针对哪个用例使用此参数,但可以像此处的示例一样在Java中使用动态参数

// 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

Naming variables like that looks very 1980-ish. 这样的变量命名看起来非常像1980年代。 Meaning pre object oriented programming. 意思是面向对象的程序设计。 So if you ever build software for a living - DON'T DO THIS. 因此,如果您曾经谋生软件,那就不要这样做。

But since it seems to be homework... 但是由于这似乎是家庭作业...

When we're talking about a named variable in Java, we mean something that's compiled. 当我们谈论Java中的命名变量时,是指已编译的内容。 Unlike in some scripting languages there is no easy way to do this in Java. 与某些脚本语言不同,在Java中没有简单的方法可以做到这一点。

So either you use a runtime compiled class like Markus Lausberg suggested. 因此,您可以使用Markus Lausberg建议的运行时编译类。
Or you cheat and use the Java Scripting API and make use of the scripting languages. 或者您作弊并使用Java Scripting API并使用脚本语言。 That way you can create code (in a String) at runtime. 这样,您可以在运行时创建代码(以字符串形式)。

I think you can generate a Java class at runtime or maybe use some script engine like Beanshell to generate the variables, you can even build the class by its bytecode. 我认为您可以在运行时生成Java类,或者可以使用Beanshell之类的脚本引擎来生成变量,甚至可以通过其字节码来构建类。 But I can't see how you will use that variables in your code, you must also create the code to work with that variables, or use reflection for that... 但是我看不到如何在代码中使用该变量,还必须创建代码以使用该变量,或者对此使用反射。

A naive solution: 一个幼稚的解决方案:
create a class with all variables from var000 to var999 with a getter for each... but that's not really dynamically! 创建一个具有从var000到var999的所有变量的类,每个变量都有一个getter ...但这并不是真正的动态!

It looks like your professor is PHP-biased on the feature ( Variable variables ), so he was thinking if that was possible in java. 看来您的教授在功能( 变量变量 )上有PHP偏见,因此他在考虑在Java中是否可行。

I personally don't think that this is possible, not in the way you are proposing. 我个人认为这是不可能的,而不是您提议的方式。 What can be done is the generation of classes at runtime, using tools like Javassist to make a more powerful reflection mechanism. 可以做的是在运行时使用Javassist之类的工具生成更强大的反射机制,以生成类。 So you can create a class that has the variables you want (string1, string2, etc.) at runtime. 因此,您可以在运行时创建一个具有所需变量(字符串1,字符串2等)的类。

However, don't forget that Variable variables is a really bad technique, which leads to bad code. 但是,请不要忘记Variable变量是一种非常糟糕的技术,它会导致错误的代码。 It might be useful on very few cases, but I really don't recommend it. 在极少数情况下,它可能很有用,但我真的不建议这样做。

Following is the way that i have implemented and helped me to fix my solution easily without much hurdles. 以下是我实施并帮助我轻松解决我的解决方案的方法,没有太多障碍。

// Creating the array List //创建数组列表

List accountList = new ArrayList(); 




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

Iterating the loop and adding the objects into the arraylist with the index. 循环并使用索引将对象添加到arraylist中。

//Retrieving the object at run time with the help of the index //借助索引在运行时检索对象

String a = accountList.get(i));

This is not possible, but this is a perfect candidate for using one of the java collections. 这是不可能的,但这是使用其中一个java集合的理想选择。

Either use a dynamically allocated array: 使用动态分配的数组:

String[] arr = new String[RUNTIME_SIZE];

Or a list which can change it's size during runtime: 或可以在运行时更改其大小的列表:

List list = new ArrayList<String>();

I do not know if I understood you correctly but if you are trying to use dynamically created names for your variables then yes, definitely - I am doing it like this: 我不知道我是否正确理解了您,但是如果您尝试为变量使用动态创建的名称,那么肯定可以-我这样做是:

// 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();

As you can see the point key here is the sign "$" that basically says "create variable name from the String that is given after this sign", and that's basically it - works like a charm for me for a few years now...hope it is what you wanted and that it helps a bit solving your problem. 如您所见,这里的指向键是符号“ $”,基本上说“从该符号后给出的字符串创建变量名”,基本上就是这样-几年来对我来说就像是一种魅力。希望这是您想要的,它可以帮助您解决问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM