8

For example, say I wanted to "extract" String[] fruits = {"Pear", "Banana", "Apple"}; into three separate variables, eg:

for (int i=0; i != fruits.length; ++i) {
    // of course there's no eval in Java
    eval("String fruit + i = " + fruits[i] + ";"); 
}

// ie: code that creates something equivalent to the following declarations:
String fruit0 = "Pear";
String fruit1 = "Banana";
String fruit2 = "Apple";

How could I do that, ignoring the "Why the heck would you want to do that?" question that you might be urged to ask me.

Similar questions have been asked many times before, but the real answer was never given, because what the OP really needed was to use a different approach. That's fine, but is this possible at all?

I have looked at reflection and it doesn't seem like there are any methods that would allow me even to add extra fields to an instance, let alone dynamically create locals.

NullUserException
  • 83,810
  • 28
  • 209
  • 234
  • The only possible way I could think is to use runtime byte code injection. As per best of my knowledge, we cannot create dynamic variables before compilation. – Usman Saleem Sep 20 '11 at 00:29
  • Let me guess, you're primarily a PHP programmer, aren't you? Am I close? – Hovercraft Full Of Eels Sep 20 '11 at 00:39
  • 1
    I think `java.lang.reflect.Proxy` is about as close as you can go. Even then you can only implement things that were defined at compile time. – clstrfsck Sep 20 '11 at 00:40
  • Yes, but you wouldn't be able to use them outside of the code you created through that mechanism (barring a consistent interface). – Dave Newton Sep 20 '11 at 00:41
  • @HovercraftFullOfEels I never used that (creating new locals on the stack) in real code in PHP/Python/JS, but the fact is, it is there if I ever need it. The other feature, dynamically adding members to an instance, is much more useful though. – NullUserException Sep 20 '11 at 01:09
  • @NullUser: I think that you're trying to have variable variable names, and if so, this is just not a concept that is part of Java. In Java variable names are not as important as they are in other languages and almost don't exist in the compiled code. If this is what you need, then justify it and probably look for another language. – Hovercraft Full Of Eels Sep 20 '11 at 01:12
  • @Hovercraft, If you think of your instance as a Serialized object then it's very easy to craft a class that has a HashMap member which you can use just about exactly like a JSON object. If you don't need to create executable chunks of code at run time (which is where eval really shines) you can get 99% of what you're looking to do with a Hash. – Yevgeny Simkin Sep 20 '11 at 01:26
  • @Dr.Dredel: Yes, I agree with your HashMap solution and have already up-voted it. – Hovercraft Full Of Eels Sep 20 '11 at 01:32

7 Answers7

17

Is it possible to create variables at runtime in Java?

The simple answer is No.

Java is a static language and does not support the injection of new variable declarations into an existing compiled program. There are alternatives (in order of decreasing usefulness / increasing difficulty):

  • Represent your "variables" as name / value pairs in a Map. Or come up with some other design that doesn't require real dynamic variables.
  • Use a scripting language that runs on the JVM and is callable from Java.
  • Use some kind of templating mechanism to generate new source code containing the declarations, and compile and load it dynamically.
  • Use a byte code manipulation library (e.g. BCEL) to create class files on the fly and then dynamically load them.

The first approach is the best. Java is a static language, and works best if you don't fight it. If this is a problem for you, maybe you are using the wrong language.

The last two are difficult / complicated and have significant performance costs. They are almost certainly not going to help ...

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
5

The question is not why you want to do it but 'what are you going to do with it?'. So suppose at runtime variable with the name fruits2 magically appeared on the stack of your method. Now what? You had to know its name at compile time to take advantage of it. Reflection will not help you access local variables.

Anyway, I would be interested if you described more detailed use case.

Alex Gitelman
  • 24,429
  • 7
  • 52
  • 49
  • @Alex, if you've ever worked with Javascript's eval, you would see how powerful and useful this feature actually is. You can construct entire code segments on the fly, based on various factors and execute them, amongst other things. If you've never *thought in this way, I realize it's hard to see the use of this, but once you get your head around the possibilities, you REALLY miss it when you move to languages that don't support it (which is most of them). – Yevgeny Simkin Sep 20 '11 at 00:43
  • @Dr.Dredel I fully agree with you. Java, however, is not a dynamic language and for as long as our discussion is limited in scope to Java (as the question is) we have to deal with it. I would surely have found good use for javascript-like `eval` in Java but it's (sadly) not present. – Alex Gitelman Sep 20 '11 at 04:37
1

The way you phrased your question, people won't understand what you're asking. I believe (if I DO understand) the answer to your question (which should be phrased: "is it possible to dynamically create variables at run time") is "not as you've presented it".

You're right, there's no analog to javascript's (very powerful, but slow and fraught with hazards "eval" function) in Java, and that is precisely what you would need to get this to do what you're hoping to do.

The closest that exists is a hashmap (which is actually pretty close) where you can designate the key at run time, and then set the value. It's fairly versatile as you can have an map that will allow for whatever type you want stored in the field.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
Yevgeny Simkin
  • 27,946
  • 39
  • 137
  • 236
0

Yes, for example, see Lombok library and specifically @log4j annotation that injects the log variable to the class

Elad Cohen
  • 79
  • 9
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 04 '22 at 16:13
0

You're not going to be able to modify a class that's already been loaded into the JVM. However, you could conceivably use ASM < http://asm.ow2.org/ > or BCEL < http://commons.apache.org/bcel/> to dynamically generate a new class that has the dynamically-defined fields.

Way more trouble than it's worth. Seriously, just use a HashMap!

avh4
  • 2,635
  • 1
  • 22
  • 25
0

Would Janino be useful for you?

Here's some code. I think it's close to what you want, but I'm not sure.

package misc;

import java.lang.reflect.InvocationTargetException;

import org.codehaus.janino.CompileException;
import org.codehaus.janino.ScriptEvaluator;
import org.codehaus.janino.Parser.ParseException;
import org.codehaus.janino.Scanner.ScanException;

public class JaninoExample {
public static void main(String[] args) {
    String in = " {\"Pear\", \"Banana\", \"Apple\"};";
    try {
        ScriptEvaluator se = new ScriptEvaluator("return new String[]"+in,String[].class);
        try {
            String[] fruits = (String[])se.evaluate(new Object[]{});
            for(String fruit:fruits){
                System.out.println(fruit);
            }
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    } catch (CompileException e) {
        e.printStackTrace();
    } catch (ParseException e) {
        e.printStackTrace();
    } catch (ScanException e) {
        e.printStackTrace();
    }

}

}

billybyte
  • 51
  • 1
  • 4
-2

Can you perhaps elaborate, not sure what you're doing different here. Of course you can create three different strings. However i believe the syntax in java is string xx = new string("DDFD");

Edit:

By this i mean, what are you trying to change here. You can allocate memory dynamically therefore you can create "variables" dynamically. HOWEVER you cannot create a "variable" in the primitive fashion such as "int x = 0;" in run time, however you can add nodes to linked lists, resize arrays, etc during run time.

oorosco
  • 246
  • 3
  • 14
  • I believe i have a faint idea, i believe someone touched on "byte injection" not sure if that is what i'm thinking about because i have the smallest notion of this. but if you can figure out memory address locations in your hash memory and stack memory you can directly correlate variable names to it by going out of bounds on paramters etc. Though i have very little knowledge about this, it's like the whole concept of buffer overflow hacking. I THINK maybe that's a direction you'd want to look into? – oorosco Sep 20 '11 at 00:37