27627


Javaのクラス名を、与えられた文字列から定義しようとしています。

そこで、Rやpythonなどのeval関数のように、文字列をコードとして評価すればよい、と考えました。  
しかし、Javaは標準で文字列を評価しないということなので、どうしてもevalのような機能を使いたい場合は、次のようにjsを呼ぶ必要があるそうです。
[Yahoo
知恵袋より](http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q13134184613)

[code]

    import javax.script.*;
    
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("js");
    engine.eval("println('Hello Script API');" + "var a,b,c; a=1.23;b=3.45;c=a*b;" + "println('a*b='+c);");
    
[/code]

ここで、評価式の中に変数定義を入れ、後のコードで定義した変数を使いたいと思っています。  
次のようなものです。

[code]

    engine.eval("int x = 8;");
    y = x*x;
    System.out.println("" + y);
    
[/code]

なぜこのようなことをしたいのかというと、次のようにまとめて書いてしまいたいクラス群があるからです。

[code]

    classNames = {"Class1", "Class2", "Class3"};
    for (int i = 0; i < classNames.length; i++){
        engine.eval(classNames[i] + " class = new " + class + "();");)
        System.out.println(class.getClass().getName());
    }
    
[/code]

しかし、この方法では、コンパイル時はclassが未定義であるため、コンパイルエラーとなってしまいます。  
コンパイルエラーを回避しつつevalを行うようなことは可能でしょうか？

上のようなループは、switch文を用いても可能なのですが、コードが冗長かつ長くなって見ずらいので、それ以外の方法で可能であればご教授願います。


CC BY-SA 3.0
2016-07-14T11:21:05.000
27621
2016-07-15T02:50:33.827
2016-07-15T01:38:23.127
14383
14383
question
javascript java
Javaのクラス名を文字列から定義したい


Java言語にはeval関数（文字列をソースコードとして評価する仕組み）的な機能は存在しません。

どうしても実現したければ、その文字列をプログラム実行時にコンパイル処理し、生成されたclassファイルを実行時にロードし、改めてクラスとして利用することも技術的には不可能ではありません。このような用途として
[Java Compiler
API](http://itpro.nikkeibp.co.jp/article/COLUMN/20081105/318537/)
が提供されてはいます。（非標準ライブラリ）

とはいえ、このような処理は相当トリッキーなため、可能な限り避けた方が良いとは思います。


CC BY-SA 3.0
2016-07-14T11:59:56.140
27622
2016-07-14T11:59:56.140
49
27621
answer


JavaScriptのevalのような方法では恐らく無理だと思います。  
単に、クラスのリストからインスタンスをまとめて生成したいだけであれば、リフレクションを使うのはいかがでしょうか？  
<http://www.ne.jp/asahi/hishidama/home/tech/java/reflection.html#h3_newInstance>


CC BY-SA 3.0
2016-07-14T12:00:33.653
27623
2016-07-14T12:00:33.653
8078
27621
answer


(前半と後半の繋がりがいまいちわからなかったのですが、後半を読む限り)実際にやりたいことは、`eval`は全く無関係で、単にクラス名を文字列で指定することであると思われましたがどうでしょう。  
であれば、次のようなコードで実現可能です。

`Class1`, `Class2` ,
`Class3`を共通的に扱いたいのであれば、それぞれに共通インタフェースを実装させることが可能である場合が多いと思います。そういった場合にはそのインタフェース型として扱えます(コード中
`1)`)。  
そうでないが汎用的に扱いたい場合、リフレクションで操作することになります(`2)`)。

[code]

    import java.lang.reflect.Method;
    
    public class Main {
    
        public static void main(final String[] args) throws Exception {
            final String[] classNames = { "Class1", "Class2", "Class3" };
    
            for (int i = 0; i < classNames.length; i++) {
                // 1) 共通インタフェースにキャスト
                final Class <? extends Executable> clazz = (Class <? extends Executable>) Class.forName(classNames[i]);
                final Executable instance = clazz.newInstance();
    
                System.out.println("class name: " + instance.getClass().getName());
                System.out.println("result: " + instance.exec());
            }
    
            System.out.println();
    
            for (int i = 0; i < classNames.length; i++) {
                // 2) リフレクション
                final Class <?> clazz = Class.forName(classNames[i]);
                final Object instance = clazz.newInstance();
                final Method method = clazz.getMethod("doOther", new Class <?>[0]);
    
                System.out.println("class name: " + instance.getClass().getName());
                System.out.println("reflection: " + method.invoke(instance, new Object[0]));
            }
    
        }
    }
    
    interface Executable {
        String exec();
    }
    
    class Class1 implements Executable {
        @Override
        public String exec() {
            return "foo";
        }
    
        public String doOther() {
            return "hoge";
        }
    }
    
    class Class2 implements Executable {
        @Override
        public String exec() {
            return "bar";
        }
    
        public String doOther() {
            return "fuga";
        }
    }
    
    class Class3 implements Executable {
        @Override
        public String exec() {
            return "baz";
        }
    
        public String doOther() {
            return "piyo";
        }
    }
    
[/code]


CC BY-SA 3.0
2016-07-14T13:12:24.540
27627
2016-07-15T02:50:33.827
2016-07-15T02:50:33.827
2808
2808
27621
answer