- PR -

インスタンスを動的にnewする方法

投稿者投稿内容
むぅ
会議室デビュー日: 2008/10/03
投稿数: 6
投稿日時: 2008-10-03 16:14
初めまして。
技術的に行き詰っているのでこちらに質問させていただきます。
Javaで、XMLからデータを読み込み、そのシナリオに対応したパラメータの型と数をnewしてインスタンスに格納したいと思っています。(シナリオ毎にパラメータ数が異なる)
XMLから抽出し、パラメータを格納するクラスを作って入れようと考えましたが、
数が変化する以上、前もって変数宣言が出来ないと思っています。(パラメータ上限なし)
for文内でnewしてもループを抜けると意味がないため、どうすればいいか困っています。
#ちなみに、この変数は別の関数をコールする際の引数として使用します。
どなたかご教授ください。よろしくお願いします。
技術的に未熟な面も多々あると思います、何したいのか分らないなどのご指摘もございましたら再度説明させていただきます。

[実行クラス]
import java.util.*;
import xmlread.xmlread;
import param.Param;

public class Scenario{
public static void main(String[] args){
try
{
String scenarioname;
int count;

//該当シナリオの読込み
xmlread call = new xmlread();
int ret = call.xmlreader(args[0]);
if(ret != 0){
System.out.println("XMLreadERROR");
}
//引数の格納
scenarioname = call.name;
count = Integer.parseInt(call.count);
//ArrayList要素の取り出し
for( int i=0 ; i<count ; i++ ){
//パラメータ番号
Object no = call.noL.get(i);
if(no > count){ break; }
//パラメータ型
Object type = call.typeL.get(i);
//パラメータ値
Object value = call.valueL.get(i);
//パラメータの格納???
        //Param param = new Param(); <…ここでは意味なし?
}
}
catch(Exception err)
{
err.printStackTrace();
}
}
}


[XML読込みクラス]
package xmlread;

import java.io.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.util.*;

public class xmlread{
//変数宣言
public String name;
public String count;
public ArrayList noL =new ArrayList();
public ArrayList typeL =new ArrayList();
public ArrayList valueL =new ArrayList();

public int xmlreader(String xml_file)
{
try
{
// ドキュメントビルダーファクトリを生成
DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
// ドキュメントビルダーを生成
DocumentBuilder builder = dbfactory.newDocumentBuilder();
// パースを実行してDocumentオブジェクトを取得
Document doc = builder.parse(new File(xml_file));
// ルート要素を取得(タグ名:scenario)
Element root = doc.getDocumentElement();

// name要素のリストを取得
NodeList namelist = root.getElementsByTagName("name");
// name要素を取得
Element nameElement = (Element)namelist.item(0);
// name要素の最初の子ノード(テキストノード)の値を取得
this.name = nameElement.getFirstChild().getNodeValue();

// count要素のリストを取得
NodeList countlist = root.getElementsByTagName("count");
// count要素を取得
Element countElement = (Element)countlist.item(0);
// count要素の最初の子ノード(テキストノード)の値を取得
this.count = countElement.getFirstChild().getNodeValue();
System.out.println("count:" + count );

// param要素のリストを取得
NodeList paramlist = root.getElementsByTagName("param");
// param要素の数だけループ
for (int i=0; i < paramlist.getLength() ; i++) {
// param要素を取得
Element element = (Element)paramlist.item(i);
// no属性の値を取得
String no = element.getAttribute("no");
noL.add(no);
// type属性の値を取得
String type = element.getAttribute("type");
typeL.add(type);
// value属性の値を取得
String value = element.getAttribute("value");
valueL.add(value);
}
return 0;

}
catch(Exception err)
{
err.printStackTrace();
return 1;
}
}
}

[読み込むXML](スキーマ定義は略)
<?xml version="1.0"?>
<scenario>
<name>data1</name>
<count>2</count>
<param no="1" type="int" value="12345"/>
<param no="2" type="String" value="test"/>
</scenario>

[パラメータ型を格納するクラス(コンストラクタのみ)]
public class Param{
protected int no;
protected String type;
protected String value;

Param(int no, String type, String value){
this.no = no;
this.type = type;
this.value = value;
}
}
mio
ぬし
会議室デビュー日: 2005/08/25
投稿数: 734
お住まい・勤務地: 神奈川県
投稿日時: 2008-10-03 17:28
何をしたいのかが不明瞭なので外してるかもしれませんが、普通インスタンス数不定のオブジェクトを管理したいならListを使えばいいと思います。
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2008-10-03 17:40
インスタンス化したいクラスの型が動的に決まる、ということでしょうか。
であれば Class.forName("型"); でいいと思います。

やろうとしていることはもしかすると Commons-Digester で実現できるかもしれません。
http://commons.apache.org/digester/
むぅ
会議室デビュー日: 2008/10/03
投稿数: 6
投稿日時: 2008-10-03 17:51
>mio様
お返事ありがとうございます。分りずらい話で申し訳ございません。
Mainのインスタンスに格納する変数は三種類で考えています。
・String シナリオ名
 …インスタンス数:1
・int パラメータ数
 …インスタンス数:1
・Param パラメータ(番号、型、値)・・・(1)
 …インスタンス数:不特定
(1)の部分の数が流動的のため、管理方法を考えているという状況です。
おっしゃっているのは、Param内容の集まり(param1,param2...)をListで管理するということでしょうか?
むぅ
会議室デビュー日: 2008/10/03
投稿数: 6
投稿日時: 2008-10-03 23:21
>インギ様
お返事ありがとうございます。遅れてしまい申し訳ございません。

引用:

インスタンス化したいクラスの型が動的に決まる、ということでしょうか。
であれば Class.forName("型"); でいいと思います。


ご指摘の通りです。
Apache WSIFのような、Objectの型を判定してインスタンス化したかったのですが、なかなかアルゴリズムが複雑で混乱しておりました。
Class.forName("型")ということは、以下のようなイメージでしょうか?
#スイマセン、理解が外れているかもしれません...
Object string;
Object int;
if(input.equals("String")){
Class.forName("java.lang.String");
}else if(input.equals("int")){
Class.forName("java.lang.Integer");
}

引用:

やろうとしていることはもしかすると Commons-Digester で実現できるかもしれません。
http://commons.apache.org/digester/


ありがとうございます。
読み込みにはJAXBを使用しようと思っていたのですが、こちらのほうがやりたいことに近い気がします。自分で探しても見つからなかったので助かります。
使用方法などについて、詳細を確認してみます。
むぅ
会議室デビュー日: 2008/10/03
投稿数: 6
投稿日時: 2008-10-07 23:42
皆様、ご教授ありがとうございました。
おかげさまで何とかやりたいことを実現することができましたので覚書の意味も込めまして、以下に報告させていただきます。

結局、Commons-DigesterはXMLで定義できるのでコードが簡略化しやすかったのですが、
ルールの単位であるタグの中の値を見ての処理だったので、JAXPで取得しました。
クラスの動的生成に関しては下記のようにしました。(一部)
public Object ChangePram(String input,String value){
Object param = new Object();
if(input.equals("String")){
param = Class.forName("java.lang.String").newInstance();
param = value;
return param;
}else if(input.equals("int")){
param = (int)Integer.parseInt(value);
return param;
}

もっとうまいやり方がありそうですが…
また、上記返信で間違えて書いたJAXBに関して、DOMなどより使えるかもしれないなと考えています。(まだよく調べていません)
以上です 一先ず、御礼まで。
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2008-10-08 01:53
コード:
if(input.equals("String")){ 

param = Class.forName("java.lang.String").newInstance();
param = value;
return param;


このコードはClass.forName() でインスタンス化した空の String オブジェクトを次の行で上書きしているので意味がありません。

シンプルに、
コード:
if(input.equals("String")){ 

return value;


と書けますね。
または、わざわざ param に代入するのであればメソッドの一番最後に一箇所だけ return 分を書いた方が流れがわかりやすいかもしれません。(好みの問題ですが)

また、
コード:
param = (int)Integer.parseInt(value); 


というコードでは parseInt で返る int 型を改めて int 型にキャストしてるのが何だか冗長です。
さらに Object 型に autoboxing されていますので、
コード:
param = Integer.valueOf(value); 


と書いた方がシンプルかもしれません。
#コンパイラが最適化して実質は同じバイトコードにしてくれそうですが。

[ メッセージ編集済み 編集者: インギ 編集日時 2008-10-08 01:56 ]
むぅ
会議室デビュー日: 2008/10/03
投稿数: 6
投稿日時: 2008-10-10 00:20
>インギ様
度重なるお返事ありがとうございます。
…テンパっているコードで申し訳ないです。
ご指摘の通り、確かに冗長な部分が多々ありました。
String型に関してそんな短いコードで実現できたとは…目から鱗です。
Class obj = (Class)Class.forName(name).newInstance();
とするなら、プリミティブ型の扱いに関してどうすればいいのか…キャストするしかないのかな…と書いていたのですが、valueOfで実現できるのですね。
また、偶然BooleanやFloatに関し、(Float)valueOf(value)と書いていましたので、Float.valueOf(value)と書き直します。
自分のコードをチェックして頂ける機会が無いので、そういう点でもとても勉強になりました。ありがとうございます。

スキルアップ/キャリアアップ(JOB@IT)