views:

877

answers:

9

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.

----Edition 001 Tue 07/28/09----
Please less complains of the usability of such constrains! More creative tricks is still welcomed! :)

A: 

Even if this were possible, how would you use them without knowing the names in advance? What's wrong with a list?

Greg Beech
The names will be predictable...as my example stated (var001, var002, var003)...you would be able to loop the names as you usually loop the indexes in Arrays...Theoretically speaking, no idea if this would work actually!
MAK
+2  A: 

You mean you want to generate variables named

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

What is the differents 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
Markus Lausberg
+1  A: 

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>();
Yuval A
For the record, its possible in PHP. See "Variable variables" in the manual.
Shadow
Sorry, I don't see any PHP tag in this question...
Yuval A
+2  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.

Stroboskop
Java Scripting API is very interesting :)Thanks for the new info!
MAK
+1  A: 

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!

Carlos Heuberger
+2  A: 

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.

tulskiy
Thanks for the info:)
MAK
+2  A: 

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.

Beska
+2  A: 

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);
        }
    }
}
Esko Luontola
Some comments on the code would really help :) thanks!
MAK
It uses the ASM library to generate a class - the byte array is in the same format as the .class files that Java compiler produces - and then loads it to the JVM using a custom class loader. ASM works at the Java bytecode level (similar to assembly code), so to understand the above code you first need to learn some Java bytecode (ASM's documentation is good for that: http://download.forge.objectweb.org/asm/asm-guide.pdf). Some other bytecode manipulation libraries may be easier to use than ASM, because they are higher level than pure bytecode. I think Javassist is one such library.
Esko Luontola
+1  A: 

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.

Edison Gustavo Muenz