Javaでインスタンス生成する場合は、コンストラクタを実行するのが普通ですが、リフレクションでもやれます。
ただ、一般的にリフレクション使うと遅いというのが懸念点の一つとして上がってきます。
というわけで、普通にコンストラクタ実行するとのリフレクション使うのでどんな差があるのかをJMH
使って測定してみます
測定条件
測定するインスタンス生成方法は以下の通りです
- 普通のコンストラクタ実行
Class#newInstance
(リフレクションを利用)Constructor#newInstance
(リフレクションを利用)
インスタンス化するクラスは以下です(デフォルトコンストラクタのみ持ちます)
final class Person { private long id; private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
実行環境のJavaは、Java7です
JMHでの測定用のコードは以下の通りとなります
import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Mode; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; public class NewInstanceBenchmark { @Benchmark public void normal() { Person p = new Person(); } @Benchmark public void clazzNewInstance() throws Exception { Person p = Person.class.newInstance(); } @Benchmark public void constructorNewInstance() throws Exception { Person p = Person.class.getDeclaredConstructor().newInstance(); } static final class Person { private long id; private String name; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(NewInstanceBenchmark.class.getSimpleName()) .warmupIterations(20) .forks(1) .mode(Mode.Throughput) .build(); new Runner(opt).run(); } }
測定結果
JMH
の実行結果は以下の通りです
# Run complete. Total time: 00:02:02 Benchmark Mode Cnt Score Error Units NewInstanceBenchmark.clazzNewInstance thrpt 20 7833794.167 ± 96565.569 ops/s NewInstanceBenchmark.constructorNewInstance thrpt 20 2182452.929 ± 70285.111 ops/s NewInstanceBenchmark.normal thrpt 20 3600508098.995 ± 18204543.613 ops/s
上記結果は以下のスループットを表しています
- NewInstanceBenchmark.clazzNewInstance ⇒
Class#newInstance
で インスタンス生成 - NewInstanceBenchmark.constructorNewInstance ⇒
Constructor#newInstance
で インスタンス生成 - NewInstanceBenchmark.normal ⇒ 普通のコンストラクタ(デフォルトコンストラクタ)実行 で インスタンス生成
Java7環境で測定したというのも関係しているとは思いますが、普通にコンストラクタ実行するのとリフレクション使うのでは雲泥の差です。
本測定においては、普通のコンストラクタ呼び出しとClass#newInstance
では450倍以上の違いが出ています。
やはり、リフレクションは必要最低限の場面で使うべきかなと感じました。