Можно ли создавать переменные во время выполнения в Java? - PullRequest
7 голосов
/ 20 сентября 2011

Например, скажем, я хотел "извлечь" String[] fruits = {"Pear", "Banana", "Apple"}; в три отдельные переменные, например:

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";

Как я мог это сделать, игнорируя «Какого чёрта ты хотел бы это сделать?» вопрос, который ты мог бы попросить меня задать.

Подобные вопросы задавались много раз прежде, но реальный ответ так и не был дан, потому что ОП действительно нуждался в том, чтобы использовать другой подход. Это нормально, но возможно ли это вообще?

Я посмотрел на отражение, и не похоже, что есть какие-либо методы, которые позволили бы мне даже добавить дополнительные поля в экземпляр, не говоря уже о динамическом создании локальных объектов.

Ответы [ 6 ]

15 голосов
/ 20 сентября 2011

Можно ли создавать переменные во время выполнения в Java?

Простой ответ - нет.

Java является статическим языком и не поддерживает внедрениеновые объявления переменных в существующей скомпилированной программе.Существуют альтернативы (в порядке уменьшения полезности / увеличения сложности):

  • Представьте ваши «переменные» в виде пар имя / значение в Map.Или придумайте другой дизайн, который не требует реальных реальных динамических переменных.
  • Используйте язык сценариев, который работает на JVM и может вызываться из Java.
  • Использоватькакой-то шаблонный механизм для генерации нового исходного кода, содержащего объявления, а также для динамической компиляции и загрузки.
  • Используйте библиотеку манипулирования байтовым кодом (например, BCEL) для создания файлов классов на лету, а затем их динамической загрузки.

Первый подход - лучший.Java - статический язык, и он лучше всего работает, если с ним не бороться.Если это проблема для вас, возможно, вы используете неправильный язык.

Последние два являются сложными / сложными и имеют значительные затраты производительности.Они почти наверняка не помогут ...

5 голосов
/ 20 сентября 2011

Вопрос не в том, почему вы хотите это сделать, а в том, «что вы собираетесь с этим делать?». Поэтому предположим, что во время выполнения переменная с именем fruits2 волшебным образом появилась в стеке вашего метода. Что теперь? Вы должны были знать его имя во время компиляции, чтобы воспользоваться этим. Отражение не поможет вам получить доступ к локальным переменным.

В любом случае, мне было бы интересно, если бы вы описали более детальный вариант использования.

1 голос
/ 20 сентября 2011

Как вы сформулировали свой вопрос, люди не поймут, о чем вы спрашиваете. Я полагаю (если я действительно понимаю) ответ на ваш вопрос (который должен быть сформулирован так: «возможно ли динамическое создание переменных во время выполнения») - «не так, как вы его представили».

Вы правы, в Java нет аналога функции javascript (очень мощной, но медленной и чреватой опасностями "eval"), и это именно то, что вам нужно, чтобы получить это, чтобы делать то, что вы надеетесь делать.

Самым близким из существующих является хэш-карта (который на самом деле довольно близок), где вы можете назначить ключ во время выполнения, а затем установить значение. Он достаточно универсален, так как вы можете иметь карту, которая позволит сохранять любой тип, который вы хотите сохранить в поле.

0 голосов
/ 20 сентября 2011

Джанино было бы полезно для вас?

Вот некоторый код. Я думаю, что это близко к тому, что вы хотите, но я не уверен.

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

}

}

0 голосов
/ 20 сентября 2011

Вы не сможете изменить класс, который уже был загружен в JVM.Однако вы можете использовать ASM <<a href="http://asm.ow2.org/" rel="nofollow">http://asm.ow2.org/> или BCEL <<a href="http://commons.apache.org/bcel/" rel="nofollow">http://commons.apache.org/bcel/>, чтобы динамически генерировать новый класс с динамически определенными полями.

Больше проблем, чем стоит,Серьезно, просто используйте HashMap!

0 голосов
/ 20 сентября 2011

Можете ли вы уточнить, не уверены, что вы делаете по-другому здесь.Конечно, вы можете создать три разные строки.Однако я полагаю, что синтаксис в Java является строкой xx = новая строка ("DDFD");

Редактировать:

Под этим я подразумеваю, что вы пытаетесь изменить здесь.Вы можете распределять память динамически, поэтому вы можете динамически создавать «переменные».ОДНАКО вы не можете создать «переменную» примитивным способом, например, «int x = 0;»однако во время выполнения вы можете добавлять узлы в связанные списки, изменять размеры массивов и т. д. во время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...