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

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

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

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

Q&A

解決済

3回答

2781閲覧

リフレクション コンストラクタが作成できない

tekondo

総合スコア26

Java

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

0グッド

0クリップ

投稿2018/10/29 11:30

編集2018/11/02 23:15

前提・実現したいこと

動的にクラスからインスタンスを作りたいです。
そのためにリフレクション機能を使おうと思っているのですが、うまく行きません。
forname()を用いて文字列からクラスを作成後、コンストラクタをconstractorを用いて作成しようとする段階でerrorが起きてしまいます。

何が原因かわかる方いらっしゃいますでしょうか?

発生している問題・エラーメッセージ

java.lang.NoSuchMethodException: enshud.s2.parser.Parser$ProgramNameToken.<init>(enshud.s2.parser.Parser$AllExp) at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.getConstructor(Class.java:1825)

該当のソースコード

実行しているメソッド

java

1void make_class(AllExp parent,String strClass){ 2 // リフレクション 3 strClass = "enshud.s2.parser.Parser$" + strClass; 4 try { 5 // クラスの取得 6 Class<?> class_name = Class.forName(strClass); 7 // インスタンスの生成 8 Constructor constructor = class_name.getConstructor(AllExp.class); 9 //ここでエラー発生 10 constructor.newInstance(parent); 11 } catch(ReflectiveOperationException e) { 12 e.printStackTrace(); 13 } 14 15}

作成したいインスタンスのクラスは以下のようになっています。

#内容修正後

java

1 public class ProgramNameToken extends AllExp{//program名 2 public ProgramNameToken(AllExp parent_exp) { 3 super(parent_exp); 4 } 5 public AllExp exp_rule() { 6 new NameToken(this); 7 return this; 8 } 9 }

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

java -JDK8

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

注意

この質問は
リンク内容に引き継ぎました。

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

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

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

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

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

euledge

2018/10/29 11:44

エラーメッセージでは、ProgramNameTokenとなっていますがクラス名はProgramTokenとなっているのはなぜ?
tekondo

2018/10/29 14:03

間違えて違うクラスを表示していました、ご指摘ありがとうございます????‍♂️
guest

回答3

0

ベストアンサー

エラーの原因は他の方の回答どおりと思います。

コンストラクタをconstractorを用いて作成しようとする段階でerror

正確にはgetConstructorでエラーが発生したというべきですね。

対処1

リフレクションにより操作する対象のクラスのメンバー(フィールドやメソッドやコンストラクターなど)を全てpublicにできるならそれが一番簡単な対処になります。

対処2

以下のようにすれば他パッケージのクラスの非publicなコンストラクターを呼び出すことができます。(無制限にできるというわけではなくSecurityExceptionが発生しないことが前提ですが)

  • getConstructorの代わりにgetDeclaredConstructorを使う。

このメソッドでpublicでないコンストラクターも参照できます。

  • setAccessibleでメンバー(本件の場合コンストラクター)のアクセス制限を外す

getDeclaredConstructorでpublicでないコンストラクターも参照できますが、そのままでは通常のアクセスガードが適用されるためnewIntanceを呼び出せません。ガードを特別に解除したい場合にはこのメソッドを使います。

例:

Test.java

Java

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

AllExp.java

java

1package b; 2 3public class AllExp { 4 AllExp parent; 5 6 AllExp(AllExp parent) { 7 this.parent = parent; 8 } 9} 10 11class ProgramToken extends AllExp { 12 ProgramToken(AllExp parent) { 13 super(parent); 14 } 15}

案1のようにコンストラクターをpublicにする方法では対象クラスが他のパッケージから好きに生成できるようになります。しかし「パッケージプライベートのままにしておきたい」という事情がある場合には案2が役立つと思います。


補記:

  1. 回答例はJava10で確認しました。Java8でも動くつもりで書いたのですが何か手落ちがあったらスミマセン。
  2. ちなみにJava10Java9でmoduleが導入されたのでたとえpublicであっても他のモジュールからのアクセスをガードできるようになりました。ですのでJava10以降を使うなら対処1がより適用しやすいものになると思います。

投稿2018/10/29 13:23

編集2018/11/03 01:00
KSwordOfHaste

総合スコア18392

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

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

tekondo

2018/10/29 14:07

アドバイスありがとうございます。 超わかりやすいです、、、 コンストラクタをpublicに変更してみて再実行したのですが、エラーが変わらず、、、 どこか勘違いしている箇所ありますでしょうか? アドバイスの中で一つ気になっている点があります。 > 対象のクラスのメンバー(フィールドやメソッドやコンストラクターなど)を全てpublicにできるなら とのことなのですが、コンストラクタ以外のメソッド等も全てpublicにしなければいけないのでしょうか?
KSwordOfHaste

2018/10/29 14:20 編集

> コンストラクター以外のメソッドも全てpublic いえ、リフレクションを用いてアクセスするメンバーだけでいいです。 > どこか勘違いしている個所 そういう場合、再現する小さなコードを示すのが常道です。具体的な事実があればすぐにわかることでも曖昧な情報だけだとすぐにわからないのがプログラミングです。 ところで、よくスタックトレースを見るとProgramNameTokenになってますね。ソースコード上にはProgramTokenクラスの定義しか書かれてませんが、ProgramNameTokenの定義はどうなっているでしょうか?実はそちらのコンストラクターをpublicにしてなかったりして?
tekondo

2018/11/02 22:53

ご回答ありがとうございました。まさにおっしゃる通りの内容ばかりでした。 public を確認して試して見たのですが、思うような結果が取得できず未だ苦戦中です。 言っていただいたことを踏まえて別の質問に改めて投げようと思います。 回答していただいてありがとうございました。
guest

0

参考URLgetConstructor(引数の型, …)の説明に

引数ありコンストラクターを返す。(引数の種類が合致するpublicなもの)

とあります。ProgramTokenのコンストラクタをpublicにしたら解決できるかもしれません。

投稿2018/10/29 11:48

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

tekondo

2018/10/29 14:05

アドバイスありがとうございます。 コンストラクタをpublicに変更してみて再実行したのですが、エラーが変わらず、、、 どこか勘違いしている箇所ありますでしょうか?
退会済みユーザー

退会済みユーザー

2018/10/29 14:37

申し訳ないですが、私にはこれ以上の回答は難しいです。お力になれずにすみません。 一応確認ですが、コードの難読・圧縮化ツールの類は使用していないでしょうか?過去に私がAndroidアプリを開発していたときに、Proguardというコード難読化ツールが、ビルド時にメソッド名などを変更していたため、メソッド名を参照して動くコードが正常に動作しないことがありました。
guest

0

Class#getConstructor

このClassオブジェクトが表すクラスの指定されたpublicコンストラクタをリフレクトするConstructorオブジェクトを返します。(以下略)

コンストラクタがpublicではないからでは?

投稿2018/10/29 11:45

swordone

総合スコア20649

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

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

tekondo

2018/10/29 14:04

アドバイスありがとうございます。 コンストラクタをpublicに変更してみて再実行したのですが、エラーが変わらず、、、 どこか勘違いしている箇所ありますでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問