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

发布于 2024-07-29 02:46:46 字数 202 浏览 7 评论 0原文

假设我需要生成变量来保存用户的一些输入(我不知道它们有多少)。 如果不使用 ArrayList、ArrayList(以及其他类型的列表和映射),我的代码可以生成(比方说)String 变量 X 次,其名称如下(字符串 var001字符串 var002字符串 var003 等)? 如果是,请提供示例代码。

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)? If yes, please provide sample code.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

眸中客 2024-08-05 02:46:46

如果您确实想做类似的事情,您可以使用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);
        }
    }
}

If you really want to do something like that, you can do it through bytecode generation using ASM or some other library.

Here is code that will generate a class named "foo.bar.ClassWithFields" that contains fields "var0" to "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.

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);
        }
    }
}
北座城市 2024-08-05 02:46:46

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

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

或者使用前面提到的 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"

编辑

似乎在内部这将使用映射:) 与属性文件、首选项 API 或 DOM 树相同(它们使用向量)。 因此,如果您的教授如此挑剔,请使用文件。

Without using Array, ArrayList (and
other kind of lists and maps)

Create files with these names. Hope that will work for your professor.

Or use the Java Scripting API mentioned before:

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). So if your professor is so picky, use files.

雪花飘飘的天空 2024-08-05 02:46:46

我还没有看到这个答案,所以我会去尝试。 编写一个只写出 Java 源代码的程序。 其中大部分可以是一个模板,您只需一个循环即可根据需要写入任意数量的“string UserString003”类型变量。

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

I haven't seen this answered yet, so I'll go for it. Write a program that just writes out Java source code. 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.

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.

治碍 2024-08-05 02:46:46

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

// 创建数组列表

List accountList = new ArrayList(); 




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

迭代循环并将对象添加到带有索引的数组列表中。

//在运行时借助索引检索对象

String a = accountList.get(i));

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.

//Retrieving the object at run time with the help of the index

String a = accountList.get(i));
失退 2024-08-05 02:46:46

像这样命名变量看起来很 1980 年代风格。 意思是前面向对象编程。
因此,如果您曾经以构建软件为生,请不要这样做。

但因为它看起来像是家庭作业……

当我们谈论 Java 中的命名变量时,我们指的是经过编译的变量。 与某些脚本语言不同,在 Java 中没有简单的方法可以做到这一点。

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

Naming variables like that looks very 1980-ish. 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. Unlike in some scripting languages there is no easy way to do this in Java.

So either you use a runtime compiled class like Markus Lausberg suggested.
Or you cheat and use the Java Scripting API and make use of the scripting languages. That way you can create code (in a String) at runtime.

青芜 2024-08-05 02:46:46

我认为你可以在运行时生成一个Java类,或者使用一些脚本引擎,如 Beanshell 来生成变量,您甚至可以通过字节码构建该类。 但我不知道如何在代码中使用这些变量,您还必须创建代码来使用这些变量,或者使用反射......

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

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. 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!

自由如风 2024-08-05 02:46:46

看来您的教授对该功能有 PHP 偏见 (变量变量< /a>),所以他在想这在java中是否可行。

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

但是,不要忘记 变量变量 确实是一个糟糕的技术,会导致糟糕的代码。 它可能在极少数情况下有用,但我真的不推荐它。

It looks like your professor is PHP-biased on the feature (Variable variables), so he was thinking if that was possible in 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. So you can create a class that has the variables you want (string1, string2, etc.) at runtime.

However, don't forget that Variable variables is a really bad technique, which leads to bad code. It might be useful on very few cases, but I really don't recommend it.

甚是思念 2024-08-05 02:46:46

您的意思是您想要生成名为

var0、var1、var2 的变量并在代码中使用它们。

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

但是

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

但我想知道,这对于您的用例是否有必要。

编辑

我现在不知道您在哪个用例中使用此参数,但您可以在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

You mean you want to generate variables named

var0, var1, var2 and use them in your code.

What is the difference when you use
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. Then you compile this class using a compiler (For example Janino) and then load the class at runtime. 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

// 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
灯下孤影 2024-08-05 02:46:46

这是不可能的,但这是使用 java 集合之一的完美候选者。

要么使用动态分配的数组:

String[] arr = new String[RUNTIME_SIZE];

要么使用可以在运行时更改其大小的列表:

List list = new ArrayList<String>();

This is not possible, but this is a perfect candidate for using one of the java collections.

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>();
兔姬 2024-08-05 02:46:46

我不知道我是否理解正确,但如果您尝试为变量使用动态创建的名称,那么是的,当然 - 我这样做是这样的:

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

正如您所看到的,这里的点键是符号“$”,基本上说“从这个符号后给出的字符串创建变量名称”,基本上就是这样 - 对我来说几年来就像一个魅力......希望这是你想要的,并且它有助于解决你的问题。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文