質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

4299閲覧

リフレクション コンストラクタが取得できない「続」

tekondo

総合スコア26

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2018/11/02 23:14

前提・実現したいこと 

前回の継続の質問です。
リフレクションを用いて動的にクラスを作成したいのですがうまく行きません。
前回の質問で色々試行錯誤したことをまとめてこちらの質問に改めて投げます。

java

1 2package enshud.s2.parser; 3import java.lang.reflect.Constructor; 4 5public class Parser { 6 public static void main(final String[] args) { 7 new Parser().run("data/ts/normal01.ts"); 8 } 9 10 public void run(final String inputFileName) { 11 make_class(); 12 } 13 14 void make_class(){ 15 try { 16 Class<?> testcl = test.class; 17 Constructor<?> cons = testcl.getDeclaredConstructor(String.class); 18 cons.newInstance("ss"); 19 } catch(ReflectiveOperationException e) { 20 e.printStackTrace(); 21 } 22 } 23 24 public class test { 25 public test(String a){ 26 } 27 } 28}

このプログラムを実行すると、make_class関数でtestcl.getDeclaredConstructorを実行した時にエラーが出ます。

### エラーメッセージ

java.lang.NoSuchMethodException: enshud.s2.parser.Parser$test.<init>(java.lang.String)

これは何故なのでしょうか?
色々試して見た結果、

java

1 public static class test { 2 public test(String a){ 3 } 4 }

とstaticをつけるとgetDeclaredConstructorはパスすることができました。しかしstaticをつけてしまうと不都合が生じるためstaticはつけたくないです。何かわかる方いらっしゃいますでしょうか?

補足情報(FW/ツールのバージョンなど)

java -JDK8

参考URL:http://www.ne.jp/asahi/hishidama/home/tech/java/reflection.html

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

staticでない内部クラスのインスタンスを生成する際にはそのクラスを囲むクラスのインスタンスが生成時に必要になります。

java

1public class Outer { 2 public class Inner { 3 } 4} 5 6... 7 8// construction 9import path_to_package.Outer; 10import path_to_package.Outer.Inner; 11 12class T { 13 public static void main(String[] args) { 14 Outer outer = new Outer(); 15 Inner inner = outer.new Inner(); 16 } 17}

内部的には上記のouterはInnerのコンストラクターの第一引数として暗黙的に仮定されるようになっています。つまり上記の例ではInnerのコンストラクターは
Inner()
ではなくて
Inner(Outer implicitOuter)
となるのです。これを前提としてgetDeclaredConstructorの引数に暗黙的な引数を追加し、Innerの生成時に外側のクラスのインスタンスを渡すと期待通りに動きます。

例:
a/Test.java

java

1package a; 2 3import b.AllExp; 4import b.Outer; 5import java.lang.reflect.Constructor; 6 7class Test { 8 public static void main(String[] args) { 9 System.out.println(Test.class.getClassLoader()); 10 System.out.println(AllExp.class.getClassLoader()); 11 Outer outer = new Outer(); 12 makeInstance(null, outer, "ProgramToken"); 13 } 14 15 static void makeInstance(AllExp parent, Outer outer, String className) { 16 className = "b.Outer$" + className; 17 try { 18 Class<?> clazz = Class.forName(className); 19 Constructor<?> ctor = clazz.getDeclaredConstructor( 20 Outer.class, AllExp.class); 21 ctor.setAccessible(true); 22 Object inst = ctor.newInstance(outer, parent); 23 System.out.println("class of instance is " 24 + inst.getClass().getCanonicalName()); 25 } catch (ReflectiveOperationException e) { 26 throw new RuntimeException(e); 27 } 28 } 29}

b/AllExp.java

java

1package b; 2 3public class AllExp { 4 AllExp parent; 5 6 AllExp(AllExp parent) { 7 this.parent = parent; 8 } 9}

b/Outer.java

package b; public class Outer { class ProgramToken extends AllExp { ProgramToken(AllExp parent) { super(parent); } } }

投稿2018/11/03 01:47

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tekondo

2018/11/03 02:49

回答を参考に作成したところ実装することができました!!! 内部クラスのコンストラクタを作成する場合は囲んでいるクラスのインスタンスを指定する必要があるんですね。とても勉強になりました!ありがとうございます!!!
KSwordOfHaste

2018/11/03 05:00

回答では省きましたが、リフレクションを用いるならある程度深いJava言語/JVMの実装面の知識が必要です。最も正確・詳細な情報源はJVM/Java言語仕様書ということになりますがこれらは分量が膨大かつ専門性が高いので誰にとって有効とは限りません。そこで一案としてjavapを使い実際のコンパイル結果(クラスファイルの中身)を観察してみることをお勧めします。そうすれば最初に挙げた例のInnerのコンストラクターが以下のように表示されるので  public b.Outer$Inner(b.Outer);   descriptor: (Lb/Outer;)V 暗黙的な引数を要求することだけはすぐにわかります。 このように「事実を調べる方法」を知っておくと「どうしたらよいか」「なぜそうなっているか」を推測・調査するための手掛かりになります。 ちなみにgetDeclaredConstructorsで全てのコンストラクターを列挙し引数を調べるなんて方法も取れますがjavapを使ったほうがずっと簡単ですね :-D
guest

0

実際の答えにはなっていませんが、気になるところを上げると
・クラスtestはめんどくさくても別ファイルにしたらいいと思います。こういうのを内部クラス、というのですが、例では内部クラスを使用していないので、やってみたらどうでしょう。別ファイルに分けると、クラスにstaticつけるとエラーだった気がするので。

投稿2018/11/02 23:36

yukkuri

総合スコア624

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tekondo

2018/11/02 23:39

ご回答ありがとうございます!!! > 例では内部クラスを使用していないので、やってみたらどうでしょう ここでの例とはなんのことでしょうか?
yukkuri

2018/11/02 23:41

例はあのサイトのことです。
tekondo

2018/11/03 02:49

無事解決できました!ありがとうございます!!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問