ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Javaの課題丸投げコミュの[質問]クラス間の変数について。

  • mixiチェック
  • このエントリーをはてなブックマークに追加
DBTest_bをメインにしたプログラムです。内容はデータベースへのアクセスになっています。

データベースにアクセスするときにDBTest_bではキーボードから必要事項を打ち込む方法をとっていますが、完成はDBTest_aにあるようにGUIから必要事項を取得したいと思っています。
※データベースへのアクセスはできています。

DBTest_aで取得したstrをDBTest_bのstrの部分に持って行きたく、そのためにいろいろ考えたのですが、僕の力ではうまく変数の受け渡しができませんでした。。。それぞれのソースはできているので併せて添削していただけますか?よろしくお願いしますm(__)m

<テキストフィールドから文字列を取得>
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class DBTest_a extends JApplet
{
private JLabel lb;
private JTextField tf;
public static String str;


public DBTest_a()
{
//コンテンツペインの取得
Container cnt = getContentPane();

//コンポーネントの作成
lb = new JLabel("お選びください。");
tf = new JTextField();

//コンテナへの追加
cnt.add(lb, BorderLayout.NORTH);
cnt.add(tf, BorderLayout.SOUTH);

//リスナの登録
tf.addActionListener(new SampleActionListener());
}

//リスナクラス
class SampleActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
JTextField tmp = (JTextField) e.getSource();
str = tmp.getText();
lb.setText(str + "ですね。");
}
}
}

----------------------------------------------
<strを渡したいクラス>
public class DBTest_b {

public static void main(String[] args) throws IOException
{
System.out.println("パスワードを入力してください。");

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

String str = br.readLine();

try {
Class.forName("com.mysql.jdbc.Driver");
System.out.println("接続します");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/attendance",
"***", "***");
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("select name, time, attendance, absence from team where PASSWORD = '" + str + "'");
while(rs.next()) {
String name = rs.getString(1);
String time = rs.getString(2);
String attendance = rs.getString(3);
//String absence = rs.getString(4);

double t = Double.parseDouble(time);
double a = Double.parseDouble(attendance);


double rate = a / t * 100;

System.out.println("名前:"+ name + "出席回数:"+ attendance + "回" + "出席率:"+ rate +"%");
}
rs.close();
st.close();
conn.close();
System.exit(0);
} catch (ClassNotFoundException e) {
System.out.println("ドライバを読み込めませんでした "+e);
} catch (SQLException e) {
System.out.println("データベース接続エラー "+e);
}
}

}

コメント(9)

(うっちー@0 さん)
> うまく変数の受け渡しができません

まず、「変数」と、「(変数に保存されている..)値」をしっかり、区別できるようにしましょう。

# 普通は、「値」を受け渡すことはできても、「変数」を受け渡すことはできないのですから..

恐らく、「受け渡し」たいのは、「変数」ではなく、「値」だろうと思います。

# 以下、それを前提に.. ( もし、本当に「『変数』を渡したい」のであれば、もう一度、尋ね直してください.. )

## ちなみに、「変数」は、「アクセスする」もので、「参照する(read)」か「変更/代入する(write)」のどちらかですね

==

さて、今回の課題で、理解しなければならないポイントは二つあると思います。

[1] 異なる Class で実現されているプログラム ( メソッド ) をどの樣に利用する(呼び出す)か ?
[2] [1] の場合に、どのような形でデータ ( 値 ) を受け渡すか ?

順番に考えて行ましょう。

==

他の Class に実現されているメソッドを利用するには、

(1) メソッド呼び出し

を使います。その方法は、そのメソッドが、インスタンスメソッドかクラスメソッドかによって、多少方法が違いますが、既に、DBTest_a/DBTest_b が理解できているのであれば、これは、問題ないでしょう。

しかし、具体的に考えるとなると、話はそれほど単純ではありません。

> DBTest_bをメインにしたプログラム

とあるので、DBTest_b の main メソッド ( DBTest_b#main ) から、DBTest_a のメソッドを呼び出したいわけですね ?

では、その呼び出したい「DBTest_a のメソッド」とはなんでしょう ?

わかりますか ? DBTest_a#SampleActionListener#actionPerformed でしょうか ? 違いますよね.. 不思議ですね.. 何故、見当たらないのでしょうか ?

実は、先程の「ポイント」では触れなかったのですが、実は、もう一つ大きな問題がありました。
それは、

[0] Java の Applet の実行と、その他の ( 普通の Application ) Program の実行の違い

です。

実は、Applet というのは、非常に特殊な実行環境を仮定して作るのが普通なのです。( まっ、Multi Media まわりの機能 [ 画像の表示だとか、音声の再生とか.. ] が便利で利用している人もいますが.. )。

# DBTest_a と DBTest_b は、それぞれ別々に実行したと思うのですが、その実行方法の違いに気が付きましたか ?

Applet を実行する時には、暗黙の内に、それ以前に Applet を実行するための「環境」となるプログラムが実行されてなければならず、その「環境」から、Applet に実装されている start メソッドが呼び出されます。

例えば、次のような ( main ) メソッドを class DBTest_a に追加してみましょう ( cf. http://mixi.jp/view_bbs.pl?id=8996746&comm_id=1017129 の #17 )。

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
public static void main ( String[] args ) {

// Applet の動作環境 ( Frame ) の作成

Frame aFrame = new Frame();

aFrame.addWindowListener( new WindowAdapter() {
public void windowClosing(WindowEvent e) {System.exit(0);}
});

aFrame.setBounds(new Rectangle(0,0,200,200));

// Applet 自身の作成

JApplet anApplet = new DBTest_a();

// Applet の初期化

anApplet.init();

// Applet を環境に追加

aFrame.add ( anApplet );
aFrame.pack();

// 環境 (Frame) の表示

aFrame.setVisible( true );

// Applet の動作開始

anApplet.start();
}
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

そうすれは、今度は、今迄と異り、

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
java DBTest_a
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

で、実行できるはずです ( 試してみましょう.. )。

しかし、実を言えば、今回の Applet を利用するという方法は、次の意味で、望ましくありません。

[0.1] Applet は特殊な実行環境を期待する ( 上記の通り )
[0.2] [0.1] の環境は、security の理由から、DB アクセスなどを利用 *させない* のが普通 ( まあ、上記のように、自分で環境を作る場合は、この問題はありませんが .. )
[0.3] Applet は、暗黙の内に Thread ( cf. http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/lang/Thread.html ) を利用するので、「コンカレントプログラミング」の考えが必要になる。

だんだん、頭が痛くなってきましたか ? そうですね ? どうしましょうか ?

実は答は簡単です。

(0) Applet を使わない

とすればよいのです。

# Applet なので、[0] の問題があるのです。

しかし、Applet を利用しないのであれば、「じゃあ、何を利用するか ?」ですが、ここでは、

(0.1) JDialog ( http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/javax/swing/JDialog.html ) を利用する。

が良いでしょう。

具体的には、

> public class DBTest_a extends JApplet

とあるのを、

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
public class DBTest_a extends JDialog
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

に変更します。

当然、これに合せて、main も、次のように変更します。

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
public static void main ( String[] args ) {
DBTest_a anDialog = new DBTest_a();

anDialog.setBounds(new Rectangle(0,0,200,200));

anDialog.setModal( true );
anDialog.setVisible( true );
}
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

どうです。かなり、すっきりしたのではないでしょうか ?

ポイントは、

(0.2) setModal ( http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/awt/Dialog.html#setModal(boolean) ) を使って、ダイアログボックスをモーダル ( 一旦表示された、閉じられるまで、プログラムを先に進めない.. cf. http://e-words.jp/w/E383A2E383BCE38380E383ABE38380E382A4E382A2E383ADE382B0.html ) 状態にする。

ということです。

[注意] このプログラムは黙っては終了しないので、Ctrl-C を入力 ( [Ctrl] キーを押しながら、[c] キーをポンと押す ) するとよいでしょう。

# これでやっと本題に戻れます。

ここで、最初に問題になった、

> その呼び出したい「DBTest_a のメソッド」とはなんでしょう ?

の答も、これで、解りましたね ? ようするに、「setVisible( true )」ということになるわけです。

# 実を言えば、これは厳密には *嘘* なのですが、今回は、この点が本質的な話題ではなく、また、初学者には、理解を進めるために、「嘘も方便」が多用されるのですが、ここでも、そのような物だと理解して頂きたいと思います。

## どこが「嘘」なのかが知りたければ、改めて質問してみてください。

==

# さて、[2] です。

(java に限らず..) 一般に、「値を ( プログラム間で.. ) 受け渡す」ために利用される典型的な方法は、

(2) 「引数(ひきすう)」あるいは、「戻り値(もどりち)」を利用する

ことです。

# 「引数」は、「呼ぶ側から呼ばれる側に値を渡す」場合に利用し、「戻り値」は「呼ばれた側から呼ぶ側に値を返す」場合に利用するのが *普通* です。

例えば、

> public class DBTest_b {
(略)
> String str = br.readLine();

では、br.readLine() を呼び出した結果、「キーボードから入力された ( 恐らく、パスワードを表現する ?) 文字列」が、「戻り値」として返ってきます。

同様にして、

> DBTest_aで取得したstrをDBTest_bのstrの部分に持って

きたいのであれば、DBTest_a のメソッド(関数)で、「戻り値」として、「str の値」を返すメソッドを考えればよいでしょう。

そこで、次のようなメソッド ( getStr() ) を追加して見ましょう。

# あー、側で「そんなことせずとも..」と思っている識者の方、僕は、原理主義者なのです ( cf. http://mixi.jp/view_bbs.pl?page=2&comm_id=1017129&id=8813675 の #37 からの議論をどうぞ.. )。

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
public String getStr() {
return str;
}
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

そして、main の最後に、

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
System.out.println ( "Input String = " + anDialog.getStr() );
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

を追加します。

そうすれば、DBTest_a を実行し、文字列を入力した後に、Window を閉じ ( るために、ウィンドウの左上隅にある [x] をクリックす ) れば、コンソール上に、入力した文字列が出力されることでしょう。

==

おっと、うっかりしていました。「これらを DBTest_b.java からどのように呼べばよいか ?」という議論でしたよね。

ここまでくれば、もう答はお解りでしょう。

DBTest_b#main の

> String str = br.readLine();

を、DBTest_a#main の中身を参考に置き換えればよいのです。

# ただし、
# System.out.println ( "Input String = " + anDialog.getStr() );
# の代りに、
# String str = anDialog.getStr();
# とします。

PS.
「プログラムが終了しない件」ですが、DBTest_b#main の最後に、

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
System.exit(0);
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

を追加すると良いでしょう。

# なぜ、こんなことになるかは、また、機会があったら..。

PS2.
実は、DBTest_a の方を main にすると、もっと話が単純になります。後学の為に、そちらも考えてみては如何がでしょうか ?

PS3
課題提出者の意図と一致するかどうかは解りませんが、DBTest_a を利用せず、JOptionPane#showInputDialog ( http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/javax/swing/JOptionPane.html#showInputDialog(java.lang.Object) ) を使えば一発なんですがねぇ.....
すごく詳しく解説していただいてとても感謝しております。本当にありがとうございます<(_ _*)>

一通り読んでみましたが、十分に理解するには少し時間が掛かりそうです(汗 でも十分理解できたときにはさらに感謝していると思います笑

また質問ができましたら、厚かましいですが、再度させてもらうと思いますが、そのときはよろしくお願い致します。
前回は大変お世話になりましたm(__)m

しかし、最後の最後が分からずにいるのでまた継続質問させていただきます。

質問は DBTest_b 内で呼び出し方法です。

---------------------------------------------------

DBTest_a DB = new DBTest_a();

String str = DBTest_a.str;

System.out.println ( "Input String = " + str );

---------------------------------------------------

をDBTest_bの main のキーボードからの入力部分と置き換えたのですが、表示させれるのは

Input String = null

です。
いろいろやってみたのですが、どうしても私にはできませんでした。これくらい自力で解決したかったのですが、ダメでした...

すいませんが、ソースを教えてもらえますでしょうか?よろしくお願いします。
2行目は
String str = DB.str;
では?

それと,この処理はDB.strになんらかの文字列が入っているという前提です.
DB.strに文字列を,文字列を代入しておかないと null になります.
ご返事ありがとうございました。

早速教えていただいたソースで試してみましたが、やっぱり null になってしまいました。確かに DB.str に何かしらが入っていないと null になってしまいますよね;

でも理想は、DBTest_bを実行すると、DBTtest_a内のプログラムが起動して、文字列をキーボードから入力できるようにして、そうするとDBTest_bでデータベースに接続できることなのですが、DBTest_bを今の状態で実行してもDBTest_aが実行されないままです。
>DBTest_a DB = new DBTest_a();
>String str = DB.str;
>System.out.println ( "Input String = " + str );

うっちーさんの頭の中では,
上記1行目でGUIが表示され,GUI部で入力を受け付けた後2行目が実行され....という感覚でしょうけど,
そうはならないと思います.
入力を受け付ける間もなく,2行目が実行されますからNULLになるでしょう.

解決策は,ぴょんぴょんさんが書いてあるとおりですから,補足程度に似たようなこと書きますが,
解決策1:DBTest_bをmainにするのを止める.
解決策2:JAppletを使わない.JDialog を使う
と変更することを薦めます.
ぴょんぴょんさんの解決策の"JOptionPane.showInputDialog"を使ったらホントに一発でした...

DBTest_aにかじりつき過ぎていたみたいです;

ありがとうございました。
(うっちー@7 さん)
> "JOptionPane.showInputDialog"を使ったらホントに一発

ひとまず、おめでとうございます。

> DBTest_aにかじりつき過ぎていた

いえ、これはこれで必要なこととかと思います。少し、拘ってみましょう。

# ここまでくれば、以下の内容も理解できるでしょう。

==

まず、#1 の [0] 以下に従って、DBTest_a に main を追加し、java DBTest_a できちんと動くことが確認できているとします ( つまり Applet のままで、実行できる形にする.. )。

次に、DBTest_b# main の

> String str = DBTest_a.str;

の前に、

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
DBTest_a.main ( null );
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

を入れます。そして、java DBTest_b とすれば、GUI 画面が表示されることが確認できます。

# やってみましょう。

ただし、不幸なことに、DBTest_a.str はまだ null のままです。

これは、

(おちくん@6 さん)
> 記1行目でGUIが表示され,GUI部で入力を受け付けた後2行目が実行さ
> れ....という感覚でしょうけど,

> そうはならない

との御指摘の通りです。

つまり、GUI の部分と DBTest_b#main は、「独立に、別々に動いている ( = Thread )」なんですね...

そして、次に、上で付け加えた行の下に、以下の「おまじない」を追加してみましょう。

-- 8< ---- 8< ---- 8< ---- 8< ---- 8< --
while ( DBTest_a.str == null ) {
System.out.println ( "Waiting .. " );
try { Thread.sleep ( 1000 ); } catch ( Exception e ) { }
}
-- 8< ---- 8< ---- 8< ---- 8< ---- 8< --

つまり、DBTest_b#main の中で、「DBTest_a.str の準備はできたか ?」と「一々、確認している」わけですね...

こうすれば、GUI 側で文字列を入力することにより、( DBTest_a.str の値がセットされ.. ) DBTest_b#main は、安心して次に進めるようになるわけです。

PS.
ただし、この方法は、「大変行儀の悪い方法 ( busy wait )」なので、「理解のために紹介した」という事をご理解ください。つまり、普通は「やってはならない方法」なのです。

# じゃあ、「普通は ?」ときかれたら、まあ、既に述べたようにモーダルダイアログを使うか、あるいは lock を使うことになりますが、後半の議論は、更に知識が必要になるので....
ぴょんぴょんをはじめ、質問に丁寧に答えてくださったみなさん。無事課題を終えることができました。
とても助かりました、ありがとうございました<(_ _*)>

最後はJSPなどを使って、ずいぶん大掛かりなものになってしまいましたが、一緒にアップした画像のようなものになりました。

本当にありがとうございました。

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Javaの課題丸投げ 更新情報

Javaの課題丸投げのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング