こちらをご覧ください。注意書きに従って自習してください。「提出課題」とある部分が最後にあります。これを作って、.javaと.classファイルを出席番号+ローマ字名前のフォルダにコピーして圧縮してください。新年最初の授業(2020年1月9日)の授業開始時間直後に、演習室からいつものように提出してくだい。
コピペして動かしてみてください。
#ref(): File not found: "list.png" at page "LectureMNP07"
import java.awt.*; import javax.swing.*; public class JListSample extends JFrame { JListSample(String title) { setTitle(title); String[] data = {"Iced Coffee", "Iced Tea", "Blend Coffee"}; JList<String> list = new JList<String>(data); JScrollPane scroll = new JScrollPane(list); scroll.setPreferredSize(new Dimension(200,100)); JPanel panel = new JPanel(); Container container = getContentPane(); container.add(scroll); } public static void main(String[] args) { JListSample sample = new JListSample("ListSample"); sample.pack(); sample.setVisible(true); sample.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
まずはシンプルなプルダウンメニューを作ってみましょう。 このプログラムは何もしません。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class JMenuSample extends JFrame implements ActionListener { public void initialize() { this.setTitle("MenuSample"); JMenuBar menubar = new JMenuBar(); JMenu menu = new JMenu("menu"); JMenuItem item1 = new JMenuItem("Sandwiches"); JMenuItem item2 = new JMenuItem("Side Orders"); JMenuItem item3 = new JMenuItem("Drinks"); menu.add(item1); menu.add(item2); menu.add(item3); menubar.add(menu); this.setJMenuBar(menubar); this.setSize(400,200); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void actionPerformed(ActionEvent e){ } public static void main(String[] args) { JMenuSample sample = new JMenuSample(); sample.initialize(); } }
メニューにはメニューを追加することもできます。 上でitem3をメニューに変更すると、これにitemを追加できます。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class JMenuSample extends JFrame implements ActionListener { public void initialize() { this.setTitle("MenuSample"); JMenuBar menubar = new JMenuBar(); JMenu menu = new JMenu("menu"); JMenuItem item1 = new JMenuItem("Sandwiches"); JMenuItem item2 = new JMenuItem("Side Orders"); JMenu item3 = new JMenu("Drinks"); menu.add(item1); menu.add(item2); menu.add(item3); JMenuItem subitem1 = new JMenuItem("Iced Coffee"); JMenuItem subitem2 = new JMenuItem("Iced Tea"); item3.add(subitem1); item3.add(subitem2); menubar.add(menu); this.setJMenuBar(menubar); this.setSize(400,200); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void actionPerformed(ActionEvent e){ } } public static void main(String[] args) { JMenuSample sample = new JMenuSample(); sample.initialize(); } }
それぞれのitemに、フレーム自身をaction Listenerとして登録すれば、イベントを受け付けることができます。 ここでは、メニューアイテムにcommandという情報をつけて、ActionPerformedではこれを使ってメニュー項目を区別しています。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class JMenuSample extends JFrame implements ActionListener { public void initialize() { this.setTitle("MenuSample"); JMenuBar menubar = new JMenuBar(); JMenu menu = new JMenu("menu"); JMenuItem item1 = new JMenuItem("Sandwiches"); item1.addActionListener(this); item1.setActionCommand("Sandwiches"); JMenuItem item2 = new JMenuItem("Side Orders"); item2.addActionListener(this); item2.setActionCommand("Side Orders"); JMenu item3 = new JMenu("Drinks"); menu.add(item1); menu.add(item2); menu.add(item3); JMenuItem subitem1 = new JMenuItem("Iced Coffee"); subitem1.addActionListener(this); subitem1.setActionCommand("Iced Coffee"); JMenuItem subitem2 = new JMenuItem("Iced Tea"); subitem2.addActionListener(this); subitem2.setActionCommand("Iced Tea"); item3.add(subitem1); item3.add(subitem2); menubar.add(menu); this.setJMenuBar(menubar); this.setSize(400,200); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void actionPerformed(ActionEvent e){ String command = e.getActionCommand(); if(command != null){ System.out.println(command); } } public static void main(String[] args) { JMenuSample sample = new JMenuSample(); sample.initialize(); } }
他のメニューの追加も試してみましょう。例えばお支払いメニュー。
次をコピペして動かしてみてください。色を選択するパネルが出ます。動作を確認してください。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class JColorChooserSample extends JFrame implements ActionListener { JButton button; JColorChooserSample(String title){ setTitle(title); button = new JButton("choose color"); button.addActionListener(this); JPanel panel = new JPanel(); panel.add(button); Container container = getContentPane(); container.add(panel); } public void actionPerformed(ActionEvent e){ JColorChooser colorchooser = new JColorChooser(); Color color = colorchooser.showDialog(this,"choose a color",Color.blue); //button.setBackground(color); button.setForeground(color); } public static void main(String[] args){ JColorChooserSample sample = new JColorChooserSample("JColorChooserSample"); sample.pack(); sample.setVisible(true); sample.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } }
次のプログラムは、テキストフィールド2個とボタン1個を表示します。 動作を確認してください。テキストフィールドに文字を入れてみてください。 イベントハンドラーが全く実装されていないので、ボタンを押しても何も起こりません。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class JTextFieldSample extends JFrame { JButton button; JTextField textleft, textright; public void initialize() { button = new JButton("left to right"); textleft= new JTextField(10); textright= new JTextField(10); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.add(textleft, BorderLayout.WEST); panel.add(textright, BorderLayout.EAST); panel.add(button, BorderLayout.SOUTH); this.getContentPane().add(panel); this.setTitle("JTextFieldSample"); this.pack(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } public static void main(String[] args){ JTextFieldSample sample = new JTextFieldSample(); sample.initialize(); } }
演習:このプログラムで、left to rightボタンを押した時に、左のテキストフィールドの内容が右に移動する(左は空になる)ように変更してください。
ヒント:JTextFieldのマニュアルを見て、テキストをゲットしたりセットするメソッドを探してください。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
ヒント:
getText()とsetText("xxx")を使います。
解答例:
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class JTextFieldSample extends JFrame implements ActionListener { JButton button; JTextField textleft, textright; public void initialize() { button = new JButton("left to right"); button.addActionListener(this); textleft= new JTextField(10); textright= new JTextField(10); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.add(textleft, BorderLayout.WEST); panel.add(textright, BorderLayout.EAST); panel.add(button, BorderLayout.SOUTH); this.getContentPane().add(panel); this.setTitle("JTextFieldSample"); this.pack(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } public void actionPerformed(ActionEvent e) { textright.setText(textleft.getText()); textleft.setText(""); } public static void main(String[] args){ JTextFieldSample sample = new JTextFieldSample(); sample.initialize(); } }
演習:このプログラムに、右のテキストフィールドをクリアするclearボタンを追加してください。 こんなのをつくってください。
ヒント:4個のアイテムをパネルにつけることになります。2 x 2のグリッドレイアウトを使ってみましょう。
panel.setLayout(new GridLayout(2,2));
この後、テキストフィールドとボタンをaddしていけば、左上から順番に割り当ててくれます。
本日のレポート:クリアボタンのあるテキストフィールドサンプルのプログラムのjavaとclassを出席番号+ローマ字名のフォルダにコピーして、圧縮して、提出してください。
解答例:
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class JTextFieldSample extends JFrame implements ActionListener { JButton button, clearButton; JTextField textleft, textright; public void initialize() { button = new JButton("left to right"); button.addActionListener(this); clearButton = new JButton("clear"); clearButton.addActionListener(this); textleft= new JTextField(10); textright= new JTextField(10); JPanel panel = new JPanel(); panel.setLayout(new GridLayout(2,2)); panel.add(textleft); panel.add(textright); panel.add(button); panel.add(clearButton); this.getContentPane().add(panel); this.setTitle("JTextFieldSample"); this.pack(); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } public void actionPerformed(ActionEvent e) { if(e.getSource()==(button)){ textright.setText(textleft.getText()); textleft.setText(""); }else{ textright.setText(""); } } public static void main(String[] args){ JTextFieldSample sample = new JTextFieldSample(); sample.initialize(); } }
ボタンを多数配置した例です。
下がプログラムです。動かしてみましょう。長いのでコピペして良いです。動作を確認してください。またレイアウト方法を確認してください。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class ComplicatedLayoutSample extends JFrame implements ActionListener { public void initialize() { JPanel panel1 = new JPanel(); JPanel panel2= new JPanel(); JPanel panel3= new JPanel(); JPanel panel4= new JPanel(); JPanel panel5= new JPanel(); panel1.setLayout(new FlowLayout()); for (int i=1; i<=3; i++) { JButton btn = new JButton("NORTH" + i); btn.addActionListener(this); panel1.add(btn); } panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS)); for (int i=1; i<=3; i++) { JButton btn = new JButton("WEST" + i); btn.addActionListener(this); panel2.add(btn); } panel3.setLayout(new GridLayout(3,2)); for (int i=1; i<=6; i++) { JButton btn = new JButton("CENTER" + i); btn.addActionListener(this); panel3.add(btn); } panel4.setLayout(new BorderLayout()); JButton btn1 = new JButton("EAST1"); btn1.addActionListener(this); panel4.add(btn1, BorderLayout.NORTH); JButton btn2 = new JButton("EAST2"); btn2.addActionListener(this); panel4.add(btn2, BorderLayout.SOUTH); panel5.setLayout(new BoxLayout(panel5, BoxLayout.X_AXIS)); for (int i=1; i<=4; i++) { JButton btn = new JButton("SOUTN" + i); btn.addActionListener(this); panel5.add(btn); } Container container = this.getContentPane(); container.add(panel1,BorderLayout.NORTH); container.add(panel2,BorderLayout.WEST); container.add(panel3,BorderLayout.CENTER); container.add(panel4,BorderLayout.EAST); container.add(panel5,BorderLayout.SOUTH); this.setSize(400,200); this.setVisible(true); } public void actionPerformed(ActionEvent e) { System.out.println( ((JButton)e.getSource()).getText() ); } public static void main(String[] args) { ComplicatedLayoutSample cls = new ComplicatedLayoutSample(); cls.initialize(); } }
コピペしてしまいましたが、動作はしっかり確認しましょう。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class ComplicatedLayoutSample extends JFrame implements ActionListener {
Action ListenerをインプレメントしたJFrameサブクラスです。
public void initialize() { JPanel panel1 = new JPanel(); JPanel panel2= new JPanel(); JPanel panel3= new JPanel(); JPanel panel4= new JPanel(); JPanel panel5= new JPanel();
5個のパネルを用意しています。動作例を見るとわかりますが、上下左右と中央の五枚のパネルを貼り付けています。
panel1.setLayout(new FlowLayout()); for (int i=1; i<=3; i++) { JButton btn = new JButton("NORTH" + i); btn.addActionListener(this); panel1.add(btn); }
最初のパネルは、「北側」に貼り付けるパネルです。(ウィンドウの上部)。 ここにNORTH + 番号の名前のボタンを3個作り、アクションリスナーに自分自身を登録して、北側パネルに貼り付けています。以下同様です。フローレイアウトを使っています。貼り付ける相手の形に合わせて柔軟に配置されます。
panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS)); for (int i=1; i<=3; i++) { JButton btn = new JButton("WEST" + i); btn.addActionListener(this); panel2.add(btn); } panel3.setLayout(new GridLayout(3,2)); for (int i=1; i<=6; i++) { JButton btn = new JButton("CENTER" + i); btn.addActionListener(this); panel3.add(btn); } panel4.setLayout(new BorderLayout()); JButton btn1 = new JButton("EAST1"); btn1.addActionListener(this); panel4.add(btn1, BorderLayout.NORTH); JButton btn2 = new JButton("EAST2"); btn2.addActionListener(this); panel4.add(btn2, BorderLayout.SOUTH); panel5.setLayout(new BoxLayout(panel5, BoxLayout.X_AXIS)); for (int i=1; i<=4; i++) { JButton btn = new JButton("SOUTN" + i); btn.addActionListener(this); panel5.add(btn); }
西側パネル、中央パネル、東側パネル、南側パネルにボタンを貼り付けています。すべてのアクションリスナーに自分自身を登録しています。ボタン配置のレイアウトは、Y軸方向のボックスレイアウト、3 x 2の格子レイアウト、ボーダーレイアウト、そしてX軸方向のボックスレイアウトです。ウィンドウをリサイズして、レイアウトの特徴を確認してください。
Container container = this.getContentPane(); container.add(panel1,BorderLayout.NORTH); container.add(panel2,BorderLayout.WEST); container.add(panel3,BorderLayout.CENTER); container.add(panel4,BorderLayout.EAST); container.add(panel5,BorderLayout.SOUTH);
次に、フレームのコンテナーを取り寄せて、これに五枚のパネルを貼り付けています。レイアウトはボーダーレイアウトで、東西南北、中央に貼り付けています。ボタンだけでなく、コンテナへのパネル貼り付けでもレイアウトが利用できまう。
this.setSize(400,200); this.setVisible(true); }
あとはサイズを調整しているだけです。
public void actionPerformed(ActionEvent e) { System.out.println( ((JButton)e.getSource()).getText() ); }
イベントリスナーのためのメソッドです。ボタンに書かれた名前をget Textで取得して表示しています。
public static void main(String[] args) { ComplicatedLayoutSample cls = new ComplicatedLayoutSample(); cls.initialize(); } }
こちらはいつものメインプログラムです。
以下のプログラムで5個のボタンをレイアウトできます。 パネルに、Border Layourのインスタンスを設定しています。 また、パネルにaddする時に、Border Layoutクラスのクラス変数を、引数に追加しています。 これで東西南北中央に配置されます。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class BorderLayoutSample extends JFrame { public void initialize() { this.setTitle("Simple Window"); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.add(new JButton("WEST"),BorderLayout.WEST); panel.add(new JButton("CENTER"),BorderLayout.CENTER); panel.add(new JButton("EAST"),BorderLayout.EAST); panel.add(new JButton("NORTH"),BorderLayout.NORTH); panel.add(new JButton("SOUTH"),BorderLayout.SOUTH); Container container = this.getContentPane(); container.add(panel); this.pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public static void main (String args[]) { BorderLayoutSample f = new BorderLayoutSample(); f.initialize(); } }
演習:このプログラムがボタンのイベントを処理するように変更して、ボタンがクリックされるとそのボタン名を表示するよう改造してください。
ヒント:
((JButton)e.getSource()).getText()
でボタンの文字を取得できます。
解答例:
イベントハンドラーでボタンの名前を表示しています。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class BorderLayoutSample extends JFrame implements ActionListener { public void initialize() { JButton[] button; this.setTitle("Simple Window"); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); button = new JButton[5]; panel.add(button[0]=new JButton("WEST"),BorderLayout.WEST); panel.add(button[1]=new JButton("CENTER"),BorderLayout.CENTER); panel.add(button[2]=new JButton("EAST"),BorderLayout.EAST); panel.add(button[3]=new JButton("NORTH"),BorderLayout.NORTH); panel.add(button[4]=new JButton("SOUTH"),BorderLayout.SOUTH); for(int i=0; i < button.length; i++) { button[i].addActionListener(this); } Container container = this.getContentPane(); container.add(panel); this.pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public void actionPerformed(ActionEvent e) { System.out.println(((JButton)e.getSource()).getText()); } public static void main (String args[]) { BorderLayoutSample f = new BorderLayoutSample(); f.initialize(); } }
解答例2:
イベントハンドラーでボタンに割り当てられたコマンドを表示しています。 上記の例よりは複雑ですが、コマンドを使うメリットはあります。 この例ではメリットを活かせていませんが、 コマンドを割り当てると、ボタンの名前を変更しても影響が出ません。また、ボタンにはわかりやすい名前をつけて、コマンドにはプログラムて扱いやすい名前をつけることも可能です。
import java.awt.*; import javax.swing.*; import java.awt.event.*; public class BorderLayoutSample extends JFrame implements ActionListener { public void initialize() { JButton[] button; this.setTitle("Simple Window"); JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); button = new JButton[5]; panel.add(button[0]=new JButton("WEST"),BorderLayout.WEST); panel.add(button[1]=new JButton("CENTER"),BorderLayout.CENTER); panel.add(button[2]=new JButton("EAST"),BorderLayout.EAST); panel.add(button[3]=new JButton("NORTH"),BorderLayout.NORTH); panel.add(button[4]=new JButton("SOUTH"),BorderLayout.SOUTH); for(int i=0; i < button.length; i++) { button[i].addActionListener(this); button[i].setActionCommand(button[i].getText()); } Container container = this.getContentPane(); container.add(panel); this.pack(); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public void actionPerformed(ActionEvent e) { System.out.println(e.getActionCommand()); } public static void main (String args[]) { BorderLayoutSample f = new BorderLayoutSample(); f.initialize(); } }
演習:このプログラムを参考にして、 上で作った二つのボタンのプログラム、Simple Buttonに対して、レイアウトマネージャのFlowLayoutを使って、左寄せ、センタリング、右寄せを試してください。そして、ウィンドウのサイズを変更した時の、ボタンの移動を観察してください。
演習のヒント
bt1 = new JButton("button1"); bt2 = new JButton("button2"); panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
FlowLayoutにはCENTER, LEFT, RIGHTなどの揃え方の指定がありますが、これをコンストラクタの引数で指定できるようです。addのところではレイアウト指定しないようです。以下を試してください。
panel.setLayout(new FlowLayout(FlowLayout.CENTER));
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
演習:button2のAction Listenerとしても、自分自身を登録してみましょう。
button2.addActionListener(this);
この結果、button1でもbutton2でも、どちらも押されればHelloと表示されるようになりました。
button1を押した時はHelloと表示され、button2を押した時はGoodbyeと表示されるように変更しましょう。
ボタンごとに違うインスタンスをadd Action Listenerで追加することも可能です。そうすれば、ボタンごとに違う動きを簡単に設定できます。
今回の例のように同じインスタンス(ここではthis)をリスナーに設定した場合であっても、action Performedメソッドの中でボタンを区別すれば可能になります。 このメソッドで受け取る引数はActio Eventのインスタンスです。 このインスタンスは、発生したイベントの情報を持っています。 Action Eventにはどういうインスタンス変数・メソッドがあるかみておきましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
今回は、この中のget Source()メソッドを使いましょう。 このメソッドで、イベントを発生したインスタンスがわかります。 正確には、イベントを発生したインスタンスへの参照がわかります。 なので、それがbutton1だったのか、button2だったのかをif文で判定して、 その結果、HelloかGoodbyeを表示すれば良いです。
ただし、今のプログラムでは、変数button1, button2はinitialize()メソッドの中で定義されているので、これが終了したら消えてしまいます。使い捨てになっています。action Performedメソッドの中からもbutton1, button2が見えるようにするためには、インスタンス変数として定義しておく必要があります。以下はヒントです。
ヒント(最初の6行です)
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SimpleButton extends JFrame implements ActionListener { JButton button1, button2; public void initialize () {
演習:このヒントを元に、button1を押した時はHelloと表示され、button2を押した時はGoodbyeと表示されるように変更しましょう。
解答例:
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SimpleButton extends JFrame implements ActionListener { JButton button1, button2; public void initialize () { this.setTitle("私が作った最初の窓"); JPanel panel = new JPanel(); button1 = new JButton("button1"); button2 = new JButton("button2"); button1.addActionListener(this); button2.addActionListener(this); panel.add(button1); panel.add(button2); Container container = this.getContentPane(); container.add(panel); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void actionPerformed (ActionEvent e) { if(e.getSource()==button1) System.out.println("Hello"); else System.out.println("Goodbye"); } public static void main(String argv[]) { SimpleButton sw = new SimpleButton(); sw.initialize(); } }
ここではボタンを区別するために、インスタンス(への参照)を比較しました。それ以外の方法もあります。 一つは、ボタンのテキスト(ボタンの上に表示されている文字)を入手して、それを比較しても良いです。 ボタンのテキストは、get Text()メソッドで入手できます。 以下のように変更すると、ボタンのテキストが表示されるようになります。 ボタンに、HelloとGoodbyeを表示しておけば、それらが表示されます。 ボタンのテキストを文字列比較して、処理を変えることも可能です。
public void actionPerformed(ActionEvent e){ System.out.println(((JButton)e.getSource()).getText()); }
もう一つは、ボタンにコマンドを書く方法です。 ボタンにsetActionCommand(String)を定義しておくと、getActionCommand()で知ることができます。 例えば、
button1.setActionCommand("hello");
としておけば、actionPerformedの中で
e.getActionCommand();
で文字列を得られます。なので、例えば、
public void actionPerformed(ActionEvent e){ System.out.println(e.getActionCommand()); }
でコマンド部分を印刷できます。コマンドを文字列比較して、処理を変えることも可能です。
SwingはJavaのパッケージで、GUIを構築するための数多くのclassが含まれています。例えば、ウィンドウを作成するためのクラス、ボタンを作成するためのクラス、メニューを作成するためのクラスなどがあります。
初期のJavaでは、AWT (Abstract Window Toolkit) というパッケージが使われていました(今でも使えます)。AWTを使っても、ウィンドウ、ボタン、メニューなどを全部作ることができます。でも、Swingに移行しています。AWTとSwingでは作れるGUIの見た目が違います。AWTは、Java独特のGUIになります。それに対して、Swingでは、稼働しているOSのGUIに近い形のアプリケーションが作れます。例えば、AWTでメニューバーを作ると、Windows風に、ウィンドウ上部にメニューバーが現れます。他のmacOSのアプリと一緒に使うと、違和感があります。それに対して、Swingでは、画面上部にメニューバーが現れます。
まずはJFrameというSwingのクラスを使います。Frameは枠のことで、ウィンドウです。 JはJavaのJです。
以下のリンクからJFrameクラスを選択して、何ができるかざっと見ておきましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
授業の最初で作ったウィンドウを出すプログラムです。
import javax.swing.JFrame; public class SimpleWindow { public static void main(String argv[]) { JFrame f = new JFrame("私が作った最初の窓"); f.setSize(200,100); f.setVisible(true); } }
このままだと、ウィンドウを閉じてもプログラムは終了しません。 ウィンドウを閉じた時に、プログラムを終了するかしないかは、アプリの設計でどちらでも可能です。がシンプルなプログラムでは、ウィンドウを閉じた時に終了する方式が多いようです。 ウィンドウを閉じるとプログラムが終了するようにしてみましょう。以下のように1行追加します。
import javax.swing.JFrame; public class SimpleWindow { public static void main(String argv[]) { JFrame f = new JFrame("私が作った最初の窓"); f.setSize(200,100); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setVisible(true); } }
このプログラムをよくみていきましょう。 mainの最初の行で、JFrameのコンストラクタを呼び出して、インスタンスを作っています。 引数付きのコンストラクタを使っています。Stringの引数を使うと、その内容がウィンドウのタイトル名になります。 作ったインスタンスはJFrameを参照する変数 f に代入されています。
mainの2行目では、JFrameのインスタンスメソッドであるsetSize()を呼んでいます。文字通り、ウィンドウのサイズを設定するメソッドです。
mainの最後の行では、setVisible()メソッドを呼んでいます。これは、ウィンドウを目に見えるように表示する機能です。作っただけでは表示されないです。
アプリケーションで使うウィンドウを作る時の流儀の一つに、素のウィンドウクラスを継承して、使いたいウィンドウをサブクラスで作る方法があります。Javaではそのような方法が、一般的です。ということで、JFrameを継承して、ウィンドウを作ってみます。上のプログラムと同じことを行いますが、やり方が違っています。以下です。
import javax.swing.JFrame; public class SimpleWindow extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); this.setSize(200,100); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); } public static void main (String argv[]) { SimpleWindow sw = new SimpleWindow(); sw.initialize(); } }
このプログラムでは、JFrameを継承して、サブクラスとしてSimpleWindowを定義しています。 なので、SimpleWindowのインスタンスは、JFrameの機能を全て使えます。 別のプログラムからSimpleWindowのインスタンスを作って表示しても良いのですが、面倒なので、自信を動かすプログラムをmainで書きました。今まで、クラスを作ってそれを動かすプログラムをmainに書いていたのと同じです。
mainでは、自分自身のインスタンスを作って、それへの参照をswという変数に代入しています。 そしてinitialize()というインスタンスメソッドを呼んでいます。
initialize()は今の所SimpleWindowで新たに定義した唯一のメンバーです。 その名の通り、自分自身の初期化を行うつもりで命名しました。 コンストラクタとして実装しても良いのですが、結構複雑な仕事をするので、 別のメソッドにしました。ちなみに、他のオブジェクト指向言語では、 newした後に、init()とかinitialize()とかのメソッドを呼ぶ方式も多いです。(例えばSmallTalk言語)。 ここではそれを真似しました。
initialize()の中で、ウィンドウのタイトルを決めて、サイズを決めて、終了オプションを指定して、setVisibleしています。
このままではウィンドウが空っぽなので、文字を表示してみましょう。 文字を表示するクラスにJLabelがあります。その名の通りラベルです。
以下のリンクからJLabelクラスを選択して、何ができるかざっと見ておきましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
基本的な使い方は以下です。まずは、インスタンスを作ります。コンストラクタの引数で、表示させる文字を指定することもできます。
JLabel label = new JLabel("Hello!");
ところで、JFrameで作ったインスタンスは、Containerというクラスのインスタンスを持っています。その名前の通り、「何かを格納するもの」です。つまりウィンドウに情報を格納する機能を持ったインスタンスです。JFrameのインスタンスに、getContentPane()というメソッドを送ると、ウィンドウに表示したい情報を格納するインスタンスを返してくれます。
Container content = this.getContentPane();
で、自分自身のコンテントペーンを返してくれます。 これに対して、上記で作ったラベルインスタンスをaddすることができます。
content.add(label);
上記の、継承を使ったプログラムによるウィンドウの中に、 Hello!という文字を出してみよう。 上で紹介した3行を、initialize()メソッドに加えれば文字を出せます。
解答例:
import javax.swing.*; import java.awt.*; public class SimpleWindow extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); JLabel label = new JLabel("Hello!"); Container content = this.getContentPane(); content.add(label); this.setSize(200,100); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String argv[]) { SimpleWindow sw = new SimpleWindow(); sw.initialize(); } }
コンテンツの大きさに合わせてウィンドウサイズを変更する機能があります。 上記のプログラムではsetSize()で変更していますが、これの代わりに、
this.pack();
というメソッドを呼び出してみましょう。以下のようになるはずです。
解答例:
import javax.swing.*; import java.awt.*; public class SimpleWindow extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); JLabel label = new JLabel("Hello!"); Container content = this.getContentPane(); content.add(label); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String argv[]) { SimpleWindow sw = new SimpleWindow(); sw.initialize(); } }
今度はウィンドウにボタンを表示してみましょう。 ボタンなので、多分JButtonというクラスがありそうです。 以下から探して、何ができるかざっと見ておきましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
上記のプログラムのJLabelのところをJButtonにすればだいたい良いようです。試してみましょう。
解答例:
import javax.swing.*; import java.awt.*; public class SimpleWindow extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); JButton button = new JButton("Hello!"); Container content = this.getContentPane(); content.add(button); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String argv[]) { SimpleWindow sw = new SimpleWindow(); sw.initialize(); } }
上のプログラムのように、 getContentPane()で得られたContainerに直接ボタンを貼付けることができます。 しかし、貼付けられるのは一つのボタンだけのようです。
2個以上のボタンを貼り付けるためには、JPanel(パネル、板)というクラスのインスタンスを作って、 これに複数のボタンを貼り付け(addする)、 そのパネルとJFrameのcontentに貼り付けます。 こんな感じのイメージです。
2個のボタンを出してみましょう。 手順としては、
です。(順番は多少前後しても構いません)
解答例:
import javax.swing.*; import java.awt.*; public class SimpleButton extends JFrame { public void initialize () { this.setTitle("私が作った最初の窓"); JPanel panel = new JPanel(); JButton button1 = new JButton("button1"); JButton button2 = new JButton("button2"); panel.add(button1); panel.add(button2); Container container = this.getContentPane(); container.add(panel); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public static void main(String argv[]) { SimpleButton sw = new SimpleButton(); sw.initialize(); } }
これからがGUIプログラミングの重要なところです。 GUIプログラミングでは、ユーザがマウスをクリックしたり、ボタンを押したり、メニューを選んだり、などのイベントが発生すると、あらかじめ用意された、それぞれのイベントに対応するメソッド(イベントハンドラー)が呼ばれます。
現在のプログラムでは,ボタンを押しても何もおこりません. ボタンが押されたイベントに対応するイベントハンドラーが無いからです。
ボタンが押されたイベントを受け取るためには,
必要があります.このインスタンスが、イベントを受け取るインスタンスになります。
上の、ボタンが2つあるプログラムで、button1が押された時にHelloと表示するプログラムを作ってみましょう。
ボタンのイベントを受け取るインスタンスは、新しく作成しても良いですが、 ここではSimpleWindowから作ったインスタンスでイベントを受け取ることにします。
現在、SimpleWindowはJFrameを継承していますが、これに加えて、Action Listenerをインプレメントすることにします。 Action Listenerをインプレメントすることは、 Action Listenerが持っているメソッドを全て用意していますという宣言になります。 この場合、そのメソッドは、actionPerformed()というメソッド一つだけです。 なので、これを用意します。そこではHelloと表示することにします。
さらに、button1のAction Listenerとして、Simple Windowのインスタンスを登録しておきます。 これは、button1にアクションが発生したら、こちらのインスタンスを使ってくださいという意味です。
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class SimpleButton extends JFrame implements ActionListener { public void initialize () { this.setTitle("私が作った最初の窓"); JPanel panel = new JPanel(); JButton button1 = new JButton("button1"); JButton button2 = new JButton("button2"); button1.addActionListener(this); panel.add(button1); panel.add(button2); Container container = this.getContentPane(); container.add(panel); this.pack(); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void actionPerformed (ActionEvent e) { System.out.println("Hello"); } public static void main(String argv[]) { SimpleButton sw = new SimpleButton(); sw.initialize(); } }
これで、button1を押した時にHelloと表示されるようになりました。 button2を押しても、何もおきません。Action Listenerが登録されていないからです。
ボタンをクリックするとHelloと表示するプログラムのjavaとclassを出席番号+ローマ字名前のフォルダにコピーして、圧縮して提出してください。
ヒント1
以下のリンクからURLクラスを選択して、調べましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
ヒント2
import java.net.*;
が必要です。
URL targetURL = new URL("http://www.ocha.ac.jp/");
でURLクラスのインスタンスが得られる。
InputStream istream = targetURL.openStream();
でこれからInputStreamのインスタンスが得られる。
InputStreamReader isreader = new InputStreamReader(istream);
でこれからInputStreamReaderのインスタンスが得られる。
BufferedReader breader = new BufferedReader( isreader );
でこれからBufferedReader のインスタンスが得られる。
ヒント3
import java.io.*; import java.net.*; public class URLTest { public static void main (String argv[]) { try { ここにプログラムを書く } catch (IOException e) { System.out.println("error..."); } } }
ヒント4:
import java.io.*; import java.net.*; public class URLTest { public static void main (String argv[]) { try { URL targetURL = new URL("http://www.ocha.ac.jp/"); InputStream istream = targetURL.openStream(); InputStreamReader isreader = new InputStreamReader(istream); BufferedReader breader = new BufferedReader( isreader ); ここで一行ずつ読み込む } catch (IOException e) { System.out.println("error..."); } } }
解答例:
import java.io.*; import java.net.*; public class URLTest { public static void main (String argv[]) { try { URL targetURL = new URL("http://www.ocha.ac.jp/"); InputStream istream = targetURL.openStream(); InputStreamReader isreader = new InputStreamReader(istream); BufferedReader breader = new BufferedReader( isreader ); String line; while((line=breader.readLine()) != null) System.out.println(line); } catch (IOException e) { System.out.println("error..."); } } }
http://siio.jp/cat.jpg
をダウンロードして、cat.jpgというファイルを作るプログラムを作ってください。 データはテキストじゃなくて、バイナリーです。
ヒント1:
InputStreamのインスタンスに対してread()メソッドを使うと1バイトのデータが得られます。読み終わると-1になります。 1バイトのデータを書き出すなら、FileOutputStreamだけで可能です。
ヒント2:
import java.io.*; import java.net.*; public class URLJpeg { public static void main (String argv[]) { try { URL targetURL = new URL("http://siio.jp/cat.jpg"); InputStream istream = targetURL.openStream(); FileOutputStream fout = new FileOutputStream("cat.jpg");
というインスタンスを作って、
istream.read()
で読んで、
fout.write(1バイト)
で書き出します。
解答例
import java.io.*; import java.net.*; //http://siio.jp/cat.jpg //をダウンロードして、cat.jpgというファイルを作るプログラム public class URLJpeg { public static void main (String argv[]) { try { URL targetURL = new URL("http://siio.jp/cat.jpg"); InputStream istream = targetURL.openStream(); FileOutputStream fout = new FileOutputStream("cat.jpg"); int aData; while((aData = istream.read()) != -1) fout.write(aData); istream.close(); fout.close(); } catch (IOException e) { System.out.println("error..."); } } }
標準入出力には、
の3種類があります。これらはJavaのクラス変数として定義されています。
それぞれの型は、
です。使えるメソッドはこちらで確認できます。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
import java.io.*; public class StandardIOTest { public static void main(String[] args) { try { //System.inからInputStreamReaderを作り、それからBufferedReaderを作る InputStreamReader ireader = new InputStreamReader (System.in); BufferedReader breaderK = new BufferedReader(ireader); System.out.println("文字列を入力してリターンを押してください"); String line = breaderK.readLine(); System.out.println("あなたが入力した文字列" + line); } catch(IOException e) { System.out.println(e); } } }
キーボードから1行入力された文字列から writer.txtという名前のテキストファイルを作るプログラムを作ってください。 完成した人から、このプログラムのjavaとclassを出席番号+ローマ字名前のフォルダにコピーして、圧縮して、提出してください。あとで解答例を出します。
e100:java siio$ java KeyToFile Hello, これはテストです。 Hello, これはテストです。 e100:java siio$ cat writer.txt Hello, これはテストです。
ヒント
import java.io.*; public class KeyToFile { public static void main(String[] args) { try { ここにプログラムを書く } catch(IOException e) { System.out.println(e); } } }
文字を読み書きするのが文字ストリームです。文字に適した処理が用意されています。 ReaderとWriterというクラスのグループがあります。
File Writerを使うと文字列を書き出すことができます。 close, flush, writeなどのメソッドがあります。 こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
また、Print Writerというクラスでは、System Out Printlnのようにprintlnに相当する機能が使えます。 Javaのいろいろなデータを書き出すのに便利です。
writer.txtというファイルに、
int x = 2020; String s = "Multimedia Programming 実習";
というJavaの変数を、printlnで書き出すプログラムを作ってください。
import java.io.*; public class PrintWriterTest{ public static void main(String[] args) { try { //writer.txtというファイルを作って文字を書き込む PrintWriter pwriter = new PrintWriter("writer.txt"); pwriter.println(2020); pwriter.println("Multimedia Programming 実習"); pwriter.close(); } catch (IOException e) { System.out.println(e); } } }
作ったファイルを hexdump してみてください
$ hexdump writer.txt 0000000 32 30 32 30 0a 4d 75 6c 74 69 6d 65 64 69 61 20 0000010 50 72 6f 67 72 61 6d 6d 69 6e 67 20 e5 ae 9f e7 0000020 bf 92 0a 0000023
hexdump -cでキャラクタ表示にもなります。
$ hexdump -c writer.txt 0000000 2 0 2 0 \n M u l t i m e d i a 0000010 P r o g r a m m i n g ? ? 237 ? 0000020 ? 222 \n 0000023
2020という数値は、int型なのですが、ASCII文字列に変換されて文字として書き出されていることがわかります。 「Multimedia Programming 実習」は、もともとが文字列なので、そのまま文字列として書き出されています。0x0Aは改行コードです。
なので、文字列を書き出している部分は、File Writerの機能を使っても同様に書き出すことが可能です。
import java.io.*; public class PrintWriterTest{ public static void main(String[] args) { try { //writer.txtというファイルを作って文字を書き込む FileWriter fwriter = new FileWriter("writer.txt"); PrintWriter pwriter = new PrintWriter(fwriter); pwriter.println(2020); //pwriter.println("Java教科書"); fwriter.write("Multimedia Programming 実習"); pwriter.close(); } catch (IOException e) { System.out.println(e); } } }
File ReaderはFile Writerと同様に文字列を読み込みます。 読み込む文字数を指定して読み込むことも可能です。 さらに便利なクラスがBuffered Readerで、こちらは改行文字までを読み込んでくれます。 こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
Buffered ReaderもFile Readerのインスタンスから作りますので、2段階のコンストラクションになります。
writer.txtというテキストファイルがあるとして、これから1行ずつ読み込んで画面表示するプログラムは以下のようになります。
public class BufferedReaderTest{ public static void main(String[] args) { try { FileReader freader = new FileReader("writer.txt"); BufferedReader breader = new BufferedReader(freader); String tmp; while( (tmp=breader.readLine() ) != null) { System.out.println(tmp); } breader.close(); } catch (IOException e) { System.out.println(e); } } }
このプログラムを参考にして、 先のPrint Writer Testに書き足して、 書き込んだデータを読み出して画面に表示するプログラムを作ってください。
ヒント:
import java.io.*; public class PrintWriterTest{ public static void main(String[] args) { try { //writer.txtというファイルを作って文字を書き込む PrintWriter pwriter = new PrintWriter("writer.txt"); pwriter.println(2020); pwriter.println("Multimedia Programming 実習"); pwriter.close(); ここに書き足す } catch (IOException e) { System.out.println(e); } } }
解答例:
import java.io.*; public class PrintWriterTest{ public static void main(String[] args) { try { //writer.txtというファイルを作って文字を書き込む PrintWriter pwriter = new PrintWriter("writer.txt"); pwriter.println(2020); pwriter.println("Multimedia Programming 実習"); pwriter.close(); //writer.txtのファイルの中身をSystem.out.printlnで表示する FileReader freader = new FileReader("writer.txt"); BufferedReader breader = new BufferedReader(freader); String tmp; while( (tmp=breader.readLine() ) != null) { System.out.println(tmp); } breader.close(); } catch (IOException e) { System.out.println(e); } } }
Javaの入出力は、ファイル、ネットワーク、キーボード、ディスプレイを対象としています。C言語に比べて、高機能な上に、ネットワークへの入出力も標準装備されているところが便利です。
(ファイル、ネットワーク、キーボード) | | 入力ストリーム | V (Javaプログラム) | | 出力ストリーム | V (ファイル、ネットワーク、ディスプレイ)
データを入出力するのがバイトストリームです。 ここでは、
を使ってみます。
こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
基本的なインスタンスメソッドは、writeとcloseです。writeには1バイトの書き込み、バイト配列の書き込みがあります。IOExceptionを投げるので、キャッチします。
write(int b)
は、int型の引数の下位1バイトを書き出します。以下のプログラムでファイルに1バイト書き出すことができます。
import java.io.*; public class FoutTest { public static void main(String[] args) { try { FileOutputStream fout = new FileOutputStream("fout.dat"); fout.write(1234); fout.close(); } catch (IOException e) { System.out.println(e); } } }
これでfout.datという名前のファイルができあがるはずです。 作ったファイルを
hexdump fout.dat
してみてください
$ hexdump fout.dat 0000000 d2 0000001
1234は0x4d2だったのでその下1バイトが書き込まれました。
こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
Javaのいろいろなデータ型を書き出すことができます。 int, long, short, float, double, booleanなどのデータを書き出します。 以下では、int型データを書き出しています。 なお、Data Output StreamはFile Output Streamの機能を利用しています。 Data Output Streamのコンストラクトには、File Output Streamのインスタンスが必要です。 なので2段階のコンストラクト作業になります。
import java.io.*; public class DoutTest { public static void main (String[] args) { try { FileOutputStream fout = new FileOutputStream("dout.dat"); DataOutputStream dout = new DataOutputStream(fout); dout.writeInt(100); dout.close(); }catch (Exception e) { System.out.println(e); } } }
これでdout.datという名前のファイルができあがるはずです。 作ったファイルを
hexdump dout.dat
してみてください
e100:java siio$ hexdump dout.dat 0000000 00 00 00 64 0000004
int型は4バイトなので4バイトのファイルが出来上がっています。100は0x000064なので、その内容のファイルです。
File/Data Output Streamにはそれぞれ対応したFile/Data Input Streamがあります。 こちらで機能を確認しましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
Javaのint型のデータで100をファイルに書いて、これを読み込む例です。
import java.io.*; public class DoutTest { public static void main (String[] args) { try { FileOutputStream fout = new FileOutputStream("dout.dat"); DataOutputStream dout = new DataOutputStream(fout); dout.writeInt(100); dout.close(); FileInputStream finput = new FileInputStream("dout.dat"); DataInputStream dinput = new DataInputStream(finput); System.out.println(dinput.readInt()); dinput.close(); }catch (Exception e) { System.out.println(e); } } }
1から100までのint型の数値をwirteIntメソッドでファイルに書き出すプログラムを書いてください。また、そのファイルをreadIntメソッドで読み込み、表示してください。
作ったファイルを
hexdump dout.dat
してみてください
解答例
import java.io.*; public class DoutTest { public static void main (String[] args) { int i; try { FileOutputStream fout = new FileOutputStream ("dout.dat"); DataOutputStream dout = new DataOutputStream(fout); for(i=1;i<101;i++) dout.writeInt(i); dout.close(); FileInputStream fin = new FileInputStream ("dout.dat"); DataInputStream din = new DataInputStream(fin); for(i=1;i<101;i++) System.out.println(din.readInt()); din.close(); } catch (FileNotFoundException e) { System.out.println(e); } catch (IOException e) { System.out.println(e); } } }
EtoJ.javaとEtoJ.classを出席番号+名前のフォルダーにコピーして、圧縮して提出してください。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
2つのインスタンスのマッッピング(対応付け)の集まりを保持するクラスです。2つのインスタンスをキー(key)と値(value)と言います。例えば、keyもvalueもどちらもStringインスタンスの場合、以下のようにして要素を追加していきます。
import java.util.*; public class EtoJ{ public static void main(String args[]) { HashMap<String,String> map = new HashMap<String,String>(); map.put("apple","りんご"); map.put("banana","バナナ"); ... } }
このプログラムで、mapインスタンスからkeyに対応するvalueを取り出すためには、
map.get("apple");
などとします。
このプログラムを拡張して、以下のように動作する英語ー日本語単語変換プログラムを作ってください。
[e100:?/Documents/java] siio% java EtoJ banana バナナ [e100:?/Documents/java] siio% java EtoJ apple りんご [e100:?/Documents/java] siio% java EtoJ Please input an English word
https://docs.oracle.com/javase/jp/8/docs/api/index.html
Linked Listと同様にインスタンスの集まりを保持するデータ構造です。
(element 1) ---> (element 2) ---> (element 3) ---> ... (element n)
だだし、同一要素を重複して保持しません。
import java.util.*; public class HashSetTest{ public static void main(String args[]){ HashSet<String> set = new HashSet<String>(); String name1="Alice"; String name2="Bob"; String name3="Cindy"; //setにname1をaddしてください //setにname2をaddしてください //setにname3をaddしてください //setに再びname1をaddしてみてください。その時の戻り値 (booleanです)の状態を表示してください。 //setの内容をIteratorを使って全部表示してください。 } }
解答例:
import java.util.*; public class HashSetTest{ public static void main(String args[]){ HashSet<String> set = new HashSet<String>(); String name1="Alice"; String name2="Bob"; String name3="Cindy"; //name1,2,3を追加 set.add(name1); set.add(name2); set.add(name3); //name1の再度追加を試みる。失敗 System.out.println(set.add(name1)); Iterator it = set.iterator(); while(it.hasNext()) System.out.println(it.next()); } }
https://docs.oracle.com/javase/jp/8/docs/api/index.html
要素があって、次の要素へのポインターを持っているような、リスト構造です。
(element 1) ---> (element 2) ---> (element 3) ---> ... ---> (element n)
次のプログラムを作ってLinked Listのメソッドを使ってみましょう。 定義とコンストラクタで<String>と書くのは、要素がStringのインスタンスだという宣言です。 昔のJavaでは不要だったのですが、今のバージョンではこのような形式で明示的に書かないといけないようです。
import java.util.*; public class LinkedListTest{ public static void main(String[] args) { LinkedList<String> list = new LinkedList<String>(); String name1="ALICE"; String name2="BOB"; //listにname1をaddしてください //listにname2をaddしてください //listの要素数を取得して表示してください //listから最初の要素をgetFirstで取り出して表示してください //listからget(1)してその結果を表示してください String name3="CINDY"; String name4="DAVE"; //listにname3をaddしてください。 //listからname1を削除してください(remove) //listにname4をaddFirstしてください。 //この結果、"DAVE" --> "BOB" --> "CINDY"となると思います。 //listの全要素にアクセスするには、Iteratorインスタンスを作ると便利です。 //以下のようにして全要素を表示してください。 Iterator it = list.iterator(); while(it.hasNext()) { String st = (String)it.next(); System.out.println(st); } //toArrayメソッドで配列を作ることもできます //以下のようにして全要素を表示してください。 Object[] names = list.toArray(); for(Object s: names) System.out.println(s); } }
解答例:
Import java.util.*; public class LinkedListTest{ public static void main(String args[]){ LinkedList<String> list = new LinkedList<String>(); String name1 = "ALICE"; String name2 = "BOB"; list.add(name1); list.add(name2); System.out.println(list.size()); System.out.println(list.getFirst()); System.out.println(list.get(1)); String name3 = "CINDY"; String name4 = "DAVE"; list.add(name3); list.remove(name1); list.addFirst(name4); Iterator it = list.iterator(); while(it.hasNext()) System.out.println(it.next()); Object[] names = list.toArray(); for(Object s: names) System.out.println(s); } }
解答例(丁寧版):
import java.util.*; public class LinkedListTest{ public static void main(String[] args) { LinkedList<String> list = new LinkedList<String>(); String name1="ALICE"; String name2="BOB"; list.add(name1); list.add(name2); String firstname=list.getFirst(); String secondname=list.get(1); System.out.println("listの要素数は" + list.size()); System.out.println("listの最初の要素は" + firstname + "2番目の要素は" + secondname); String name3="CINDY"; String name4="DAVE"; list.add(name3); list.remove(name1); list.addFirst(name4); Iterator it = list.iterator(); System.out.println("要素の走査"); while(it.hasNext()){ String st = (String)it.next(); System.out.println(st); } System.out.println("要素の走査 by toArray()"); Object[] names = list.toArray(); for(Object s: names) System.out.println(s); } }
以下のリンクからStringクラスを選択して、何ができるかざっと見ておきましょう。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
public class TestString { public static void main (String argue[]) { String str = "Hello Java World"; //このstrを表示してください(System out.printlnを使う) //strの長さを表示してください(.lengthを使う)) //strの3要素目の文字を表示してください //最初にaが現れる位置を表示してください //最後の文字aが現れる位置を表示してください //辞書式で比較してstrと次のstr2のどちらが先に現れるかを表示してください(compareToを使う) String str2="Hello World"; //strの6要素目から始まる部分文字列を作り表示して表示してください。 //int型をString型に変換してください。 int v2020=2020; String s2020 = String.valueOf(v2020); } }
解答例:
public class TestString{ public static void main(String args[]){ String str = "Hello Java World"; System.out.println(str); System.out.println(str.length()); System.out.println(str.charAt(3)); System.out.println(str.indexOf('a')); String str2 = "Hello World"; System.out.println(str.compareTo(str2)); System.out.println(str2.compareTo(str)); System.out.println(str.substring(6)); int v2020=2020; String s2020 = String.valueOf(v2020); System.out.println(s2020); } }
public class TestString { public static void main(String argv[]) { System.out.println(argv[0]); } }
[e100:?/Documents/java] siio% java TestString ochanomizu ochanomizu uzimonahco [e100:?/Documents/java] siio%
さらには、引数がない場合は引数入力を促すことを表示してみよう。
[e100:?/Documents/java] siio% java TestString please input a word [e100:?/Documents/java] siio%
解答例:
public class TestString { public static void main (String argv[]) { try{ System.out.println(argv[0]); int len = argv[0].length(); for(int i = len - 1; i>=0; i--) { System.out.print(argv[0].charAt(i)); } System.out.println(); } catch (Exception e) { System.out.println("please input a word"); } } }
C言語では、エラーが出そうな処理をする場合は、エラーが発生するかどうかをステップごとにif文でチェックして、対処していました。プログラムが読みにくく煩雑になりがちです。
現代的な言語では、プログラムの処理をブロックでまとめて、その部分から発生したエラーを別の部分で受け取って処理をする書き方ができます。
Javaの多くのメソッドが標準的なエラー処理をサポートしています。また、自分でエラー処理を設計することも可能です。ただ、この授業の範囲では、自分でエラー処理を設計することはないと思います。標準的な機能の利用を練習しておきます。
次のプログラムを作って試してください。 引数が2個あることを前提としています。 なので、引数が少ないとエラーが出ます。確認してください。
public class TestException { public static void main(String argv[]){ System.out.println(argv[0]+" "+argv[1]); System.out.println("Nice to meet you."); } }
エラーが出る可能性のある場所をtryでくくっておき、 エラーが出たらそれを捕捉する処置をcatchで指定します。
public class TestException { public static void main(String argv[]){ try{ System.out.println(argv[0]+" "+argv[1]); System.out.println("Nice to meet you."); } catch (Exception e) { System.out.println("please input 2 words."); } } }
作成したOsaifuUSD.javaとOsaifuUSD.classをいつものように出席番号と名前のフォルダにコピーして、圧縮して提出してください。
サブクラスもちゃんとしたクラスですので、インスタンスを作ったらそのクラス型の変数に代入します。 例えば、ParentというクラスからChildというサブクラスを作ったとします。通常は、
Child x = new Child();
として使います。ここで親のクラスの変数に代入することもできます。
Parent y = new Child();
しかし、親のインスタンスを、子の型の変数には代入できません。
Child z = new Parent(); //これはできない
仕組みを考えれば理由は明白です。サブクラスは、スーパークラスの機能を全部持っているので、インスタンスを親の型にキャストしても問題ありません。逆に、親の型をサブクラスの型に変換すると、拡張された部分のメンバーを呼び出されたときに、対応できません。
instanceofという演算子があります。上記の例では、
if ( x instanceof Child) {} if ( x instanceof Parent) {{}
とするとifの中の判定はどちらもtrueです。あるクラスのインスタンスは、そのクラスのインスタンスでもあり、そのスーパークラスのインスタンスでもあるのです。
抽象クラスは、インスタンスを作れないクラスです。 いくつかのクラスの上位概念をまとめる役割があります。 例えば、犬クラス、猫クラスというクラスがあって、それらの上位概念として動物クラスを作ったとします。 その世界では、犬や猫のインスタンスは作れても、動物のインスタンスは作れないという設定にするのが自然かもしれません。 としたら、動物クラスは抽象クラスになります。 定義のオプションにabstractと書きます。
abstract class Animal {}
この授業で抽象クラスを作成することはないと思いますが、マニュアルを見て発見したクラスのインスタンスを作ろうとすると、「抽象クラスだからインスタンスは作れない」というエラーが出ることがあります。そのクラスのサブクラスを探して、それを使ってください。
Readerは抽象クラスです。下のリンクからReaderを探してみてください。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
抽象クラスと同様に、特定のメソッドがabstractと定義されることもあるようです。稀なケースだと思います。この場合も、サブクラスでオーバーライドして定義する必要があります。
public abstract void xxxx();
クラスの定義にfinalをつけることができます。これ以上継承して欲しくない場合につけます。
final class XXXX {}
メソッドの定義につけることもできます。サブクラスでオーバーライドして欲しくない場合に使います。
public final void XXXX(){}
抽象クラスに似ていますがクラスではないので、インスタンス化もサブクラス作成もできません。 抽象メソッドと定数だけが定義されています。 この授業でインタフェースを定義することはないと思いますが、たくさん利用します。 インタフェースには空のメソッドが定義されています。 そのメソッドを実装していますという宣言にimplementsという予約語を使います。 例えば、MovableとErasableというインタフェースが定義されていて、 クラスの定義で、これらを実装しているという宣言は、以下のように書きます。
class MyShape implements Movable, Erasable {}
このクラスでは、Movable, Erasableで定義されているメソッドを全て実装していないといけません。 ややこしいですが、後の授業で、実例がたくさん出てきますので、そこでまた理解してください。
Mouse Listenerはインタフェースの例です。下のリンクから探してみてください。
https://docs.oracle.com/javase/jp/8/docs/api/index.html
次回またはその次くらいの授業で、小テストを行います。 以下の内容が理解できるように、整理しておいてください。
以下のプログラムの中で、 クラス、インスタンス、サブクラス、スーパクラス、クラスメソッド、インスタンスメソッドがどれであり、 インスタンス化、継承がどこで行われているのか確認してください。 (importで始まる一行目はまだ説明していない内容なので小テストでは扱いません。無視してください)
import javax.swing.JFrame; public class SampleWindow extends JFrame { public static void main(String args[]) { SampleWindow w = new SampleWindow(); w.setVisible(true); } }
サブクラスに、スーパークラスと同じ名前と引数のメソッドを書くこともできます。 これをオーバライドト言います。 一つのクラスの中で、名前が同じメソッドを定義することをオーバーロードという言葉でお話ししました。 似ていますが、オーバーライドは、引数のパターンも同じです。 スーパークラスのメソッドを置き換えるものです。 ここでは、スーパークラスのprint()メソッドをサブクラスでオーバーライドしてみます。
オーバーライドすると、通常(thisが使われる場合)はサブクラスで定義されたメソッドが実行されます。 つまりサブクラスの定義の中で、
print(); this.print();
はどちらもサブクラスのprint()が呼び出されます。 でも、明示的にスーパークラスで定義された方のメソッドを実行することも可能です。 その場合は、メソッドを呼び出すときにsuperと追記します。以下のようにします。
super.print();
OsaifuUSDにprint()メソッドを追加して、 円表示の次の行に ( xxx USD ) と残高をUSD表示するようにしてください。 円表示を行う部分はスーパークラスOsaifuのインスタンスメソッドprint()を利用することを考えてみてください。
public void print() { super.print(); System.out.println("( " + (okane / 90) + " usd )" ); }
入出金のメソッドの中で、親の入出金メソッドを活用してみましょう。
public class OsaifuUSD extends Osaifu { public int outUSD(int usd) { return ( out( use * 90) / 90 ); } public void inUSD(int usd) { in( usd * 90 ); } … }
このプログラムの中のoutメソッドとinメソッドは、親のクラスで定義されたメソッドです。 outメソッドで残金がマイナスにならないように処理してあれば、そのまま仕組みを利用することができます。
親のメソッドを呼ぶことを明示的に書くためにsuper.をつかってもよいです。
public class OsaifuUSD extends Osaifu { public int outUSD(int usd) { return ( super.out( use * 90) / 90 ); } public void inUSD(int usd) { super.in( usd * 90 ); } … }
public class OsaifuUSD extends Osaifu {
public static void main(String argv[]) { OsaifuUSD saifu1= new OsaifuUSD(); OsaifuUSD saifu2=new OsaifuUSD(); saifu1.in(1000); saifu2.inUSD(5); saifu1.print(); saifu2.print(); saifu2.inUSD(saifu1.outUSD(2)); saifu1.print(); saifu2.print(); }
一番シンプルな解答例です。残高がマイナスになることは考慮していません。
public class OsaifuUSD extends Osaifu { public int outUSD(int usd) { okane-=usd * 90; return usd; } public void inUSD(int usd) { okane+=usd * 90; } public static void main(String argv[]) { OsaifuUSD saifu1 = new OsaifuUSD(); OsaifuUSD saifu2 = new OsaifuUSD(); saifu1.in(1000); saifu2.inUSD(5); saifu1.print(); saifu2.print(); saifu2.inUSD(saifu1.outUSD(2)); saifu1.print(); saifu2.print(); } }
大昔の授業で使ったプログラムを使い続けているので、為替レートが90円になっています。 多分現在の為替レートとはかけ離れています。 (スクリーンショットを撮りなおすのが面倒なので、古いレートのままになっています) 為替レートを変数として持たせるとしたら、どうしたら良いでしょうか?
のどちらにするか、考えてみましょう。
[解答]インスタンスで共通の情報ですので、おそらくクラス変数で定義するのが良いと思います。
オブジェクト指向言語では、クラスを拡張するいくつかの方法が導入されています。 Javaなどで一般的な手法は、継承です。引き継ぐということです。
すでにあるクラスの機能を拡張して、新しいクラスを作ることを考えます。 拡張する部分は新しく作るのですが、拡張しない部分は、古いクラスのまま使いたいところです。 通常は、古いクラスをコピーして、機能拡張して新しいクラスを作ることが考えられます。 でも、古いクラスの方も、そのまま使われ続けて、改良され続けるとしたら、新しいクラスにコピーした部分には反映されないことになります。
そこで継承を使います。
例えば、たい焼きの焼き型で説明します。 とても気に入った焼き型があるけど、しっぽに模様がないのだけが不満というケースを考えてみます。 そこで、現在の焼き型を親として、継承する新しい焼き型を作ります。 継承したクラスで定義すると、それだけが差分として使われます。 なので、しっぽの模様だけ定義しておけば、あとは全て親の機能が使われます。 子クラスの中身は、極端な場合、空っぽでも良いです。定義されないメンバーは全て親のメンバーが使われます。
ということで、 別のクラスを継承することで、 差分だけを書いて機能を拡張していくことができます。
Point pt1 = new Point(10,20); Point pt2 = pt1; Point pt3 = new Point(10,20);
この時、
if(pt1 == pt2)
という判断をするとこれはtrueになります。
しかし
if(pt1 == pt3)
という判断をすると結果はfalsです。
参照先が同じなのか、その中のインスタンス変数が同じなのかの違いです。インスタンス変数が同じかどうかは、その変数の値を直接調べて比較する必要があります。例えば、
if( ( pt1.x == pt3.x) && (pt1.y == pt3.y) )
のようにします。
C言語ではmallocでメモリー確保した後、これを使わなくなったところでfreeしてシステムに返す必要がありました。そうしないと、どんどんメモリーを使ってしまうことになる可能性があります。この現象をメモリーリーク(メモリー漏洩)と呼ぶこともあります。オブジェクト指向言語でインスタンスを作る場合もシステムからメモリーを確保しています。これをシステムに返却する作業が必要な言語と、不要な言語があります。返却不要な言語は、使われなくなったメモリー領域を時々チェックして、自動的に返却してくれます。このような作業を(使われなくなった)ゴミ(のような領域を)集めると呼びます。ガーエージコレクションです。Javaではガーベージコレクションを行なってくれますので、newで確保した領域を、プログラマが明示的に返却する必要はありません。
インスタンスが破棄されるときに、何か特別な処置をしてほしいことがあります。例えば、インスタンスの中で入力をオープンして、破棄されるときにはクローズしたいという場合です。その場合は、finalize()メソッドを用意しておきます。そうすると、ガーベージコレクション対象になったところで、finalize()メソッドを自動的に起動してくれます。このメソッドのことをファイナラーザーとも呼びます。
先に述べたように、インスタンス変数は、コンストラクタで初期化ができます。では、クラス変数はどうやって初期化するのでしょうか。
一つは、定義する場所で初期化できます。
public class TestStatic [ static int x = 10; y = 20;
ここでxはクラス変数で、yはインスタンス変数です。どちらも定義するところで初期化しています。
複雑な初期化をしたい場合は、staticイニシャライザを使用します。 例えば、10個の要素からなる配列を用意して、それの内容を添字の自乗になるよう初期化するには以下のようにします。
public class TestStatic { static int[] array; static { array = new int[10]; for (int I = 0; I < array.length; I++) array[I] = I * I; }
変数の宣言にfinalをつけると、その変数の値が変更の対象にならなくなります。クラス変数にfinalをつければ、定数を宣言する用途に使えます。C言語で#define文で定数を定義するような使い方ができます。
final static double PI = 3.14159265;
コンストラクタはインスタンスが生成される時に自動的に呼び出されるメソッドです。コンストラクタを利用してインスタンスを初期化することができます。コンストラクタは「クラス名と同じ名前で、戻り値のないメソッド」です。先のPointクラスにコンストラクタを追加してみました。
public class Point{ int x, y; Point() { x = y = 0; } Point(int pix, int pty) { x = ptx; y= pty; } 省略 }
インスタンスを生成する際の演算子newのあとに指定するのは、実はコンストラクタだったのです。コンストラクタは、演算子newとの組み合わせでのみ使用されます。上記で指定したコンストラクタは、次のように使われます。
Point pt1 = new Point(); Point pt2 = new Point(10, 20);
これで、最初のコンストラクタと、2番目のコンストラクタが呼び出されます。コンストラクタはnewを使用する時にしか使えません。
コンストラクタから他のメソッドを呼び出すことも可能です。例えばx,yを設定するメソッドがすでにあれば以下のように指定できます。
Point(int pix, int pty) { set(ptx, pty); } void set(int ptx, int pty) { this.x = ptx; this.y = pty; }
コンストラクタの中でコンストラクタを呼び出すこともできます。
Point() { this(0, 0); }
これはコンストラクタPoint (x, y)を呼び出しています。thisの使い方が今までと違って特殊です。
ことができるコンストラクタを作りましょう。
これをmainから呼んで、上記のプログラムと同じことをするためには、
Osaifu saifu1 = new Osaifu(1000);//インスタンスを作る //最初の保持金額を1000円にする Osaifu saifu2 = new Osaifu(500);//インスタンスを作る //最初の保持金額を500円にする
とすれば良いです。
Osaifu.javaとclassを前回と同様にフォルダにコピーして、圧縮して提出してください。
以下のコンストラクタを作ることになります。
Osaifu() { okane = 0; } Osaifu(int x) { okane = x; }
これは以下のように書いても良いです。
Osaifu() { this(0); } Osaifu(int x) { okane = x; }
double distance ( int ptx, int pty, int ptz ) { int dx = ptx - this.x; int dy = pty - this.y; int dz = ptz - this.z; return Math.sqrt(dx * dx + dy * dy + dz * dz); } double distance ( Point3D p ) { return this.distance(p.getx(), p.gety(), p.getz()); }
double distance ( int ptx, int pty ) { int dx = ptx - this.x; int dy = pty - this.y; return Math.sqrt(dx * dx + dy * dy); } double distance ( Point p ) { return this.distance(p.getx(), p.gety()); }
distanceという名前は同じでも、引数の違いで、異なる動作をさせることができます。
public static void main(String argv[]) { Osaifu saifu1 = new Osaifu(); Osaifu saifu2 = new Osaifu(); saifu1.in(1000); saifu2.in(500); saifu1.print(); saifu2.print(); saifu2.in(saifu1.out(200)); saifu1.print(); saifu2.print(); }
public class Osaifu { int okane; public void in (int x) { okane += x; } public int out(int x) { okane -= x; return x; } public void print() { System.out.println( "okane = " + okane +" yen"); } public static void main(String argv[]) { Osaifu saifu1 = new Osaifu(); Osaifu saifu2 = new Osaifu(); saifu1.in(1000); saifu2.in(500); saifu1.print(); saifu2.print(); saifu2.in(saifu1.out(200)); saifu1.print(); saifu2.print(); } }
public int out(int x) { if(x < okane ) { okane = okane -x; return x; } else { int nokori = okane; okane =0; return nokori; } }
C言語の構造体のように変数にアクセスできます。 でも、オブジェクト指向の設計では、外部からは極力変数にアクセスさせない設計が良いと言われています。 変数にアクセスするには、アクセス用のメソッドを使うのが良いと言うことです。 これにより、 変数の型などを将来変更してもメソッドの書き換えで対応できるからです。 修飾子をprivateにすると、クラスの外からアクセスできなくなって、保護できます。 そして、アクセス用のメソッドを書いておきます。
例えば、Pointクラスでしたら以下のようにします。
public class Point { private int x, y; void set(int newx, int newy) {this.x=newx; this.y=newy;} int getx() { return this.x;} int gety() { return this.y;} void print () { System.out.println(this.x + ", " + this.y); } public static void main(String argv[]) { Point pt1= new Point(); Point pt2 = new Point(); pt1.set(10,20); pt2.set(-pt1.getx(), -pt1.gety()); pt1.print(); pt2.print(); } }
Point3Dのメソッドを充実させて次のmain()メソッドで
10, 20, 30 -10, -20, -30
という結果が出るようにしましょう
public static void main(String argv[]) { Point3D pt1 = new Point3D(); Point3D pt2 = new Point3D(); pt1.set(10, 20, 30);//インスタンス変数を設定 pt2.set(-pt1.getx(), -pt1.gety(), -pt1.getz()); pt1.print();//インスタンスメソッド呼出 pt2.print(); }
print()メソッドの他に、もう少し複雑な計算をするメソッドを考えてみましょう。特定の座標を指定した場合に、その座標との距離をdouble型で返すメソッドです。平方根を計算するMathクラスのクラスメソッドを使っています。
double distance ( int ptx, int pty ) { int dx = ptx - this.x; int dy = pty - this.y; return Math.sqrt(dx * dx + dy * dy ); }
今度は、座標ではなくて、他のPointインスタンスを引数にして、自分の点から、引数で与えられた点までの距離を返すメソッドと考えてみます。こんなメソッドです。
double distance ( Point p ) { int dx = p.getx() - this.x; int dy = p.gety() - this.y; return Math.sqrt(dx * dx + dy * dy ); }
この2つのメソッドは、どちらもPointクラスに実装することができます。よく見ると、先のメソッドと名前が同じです。C言語では名前が同じ関数を定義できませんでした。オブジェクト指向の言語では、引数の種類・数が違えば、同じ名前の関数を定義できます。引数を含めて関数を識別してくれます。このことを、多重定義、もしくはオーバーロードと呼びます。
違う関数ですので、片方のdistanceの中から、もう一方のdistanceを呼び出すこともできます。なので、以下のように定義することもできます。
double distance ( int ptx, int pty ) { int dx = ptx - this.x; int dy = pty - this.y; return Math.sqrt(dx * dx + dy * dy ); } double distance ( Point p ) { return this.distance(p.getx(), p.gety()); }
Point3Dに、
次のmain()メソッドで
10, 20, 30 -10, -20, -30 74.83314773547883
という結果が出るようにしましょう
public static void main(String argv[]) { Point3D pt1 = new Point3D(); Point3D pt2 = new Point3D(); pt1.set(10, 20, 30);//インスタンス変数を設定 pt2.set(-pt1.getx(), -pt1.gety(), -pt1.getz()); pt1.print();//インスタンスメソッド呼出 pt2.print(); System.out.println(pt1.distance(pt2)); }
クラス変数、クラスメソッド、インスタンス変数、インスタンスメソッドのことをメンバーと呼ぶこともあります。クラスやインスタンスを構成するメンバーという意味です。上記で説明したように、メンバーを指定するには、そのメンバーが属しているクラスまたはインスタンス(これらをまとめてオブジェクトとも呼びます)を書いて、そのあとにピリオドを書いて、メンバーを指定します。もう一度復習すると、クラスならば、
Math.PI
でクラスMathのクラス変数のPIにアクセスできます(円周率が返ってきます)。
インスタンスならば、クラスからインスタンスを生成した後で、ピリオドでアクセスします。
Point pt1 = new Point(); pt1.print();
このようにメンバーにアクセスするには、そのメンバーが属しているオブジェクトを指定するのが正式なやり方です。ただし、同じオブジェクトの中のメンバーを指定する場合には、オブジェクトを略しても良いです。例えば、先のPointの例で、
public class Point { int x, y; void print() { System.out.println(x + ", " + y); } }
と、書いてあります。インスタンスメソッドのprint()の中で、xとyを指定しています。これは自分自身のインスタンス変数です。なのでピリオドで指定していません。省略できるからです。
これをインスタンスの名前を指定して書くことはできるでしょうか?よく考えるととても難しいです。まずは、これは設計図段階での記述なので、これから作られたインスタンスにどのような名前がつけられるかわかりません。また、特定の名前を想定すると、別の名前をつけられた時に参照できないかもしれません。このような場合でも、自分自身のメンバーを指定しているのだということを明示的に書く方法があります。それがthisです。上の例は、
public class Point { int x, y; void print() { System.out.println(this.x + ", " + this.y); } }
と書くこともできます。メソッドの中で一時的に宣言した変数ではなくて、メンバーにアクセスしているのだということがわかりやすいので、プログラムも読みやすくなります。thisは、積極的に使いましょう。
修飾子の説明:
などから、今までお馴染みの、
public static void main (String args[]) {}
は、どいういう意味だったでしょうか?考えてみてください。
さらに説明すると、クラスメソッドmainは特別なメソッドで、javaコマンドが実行するメソッドです。なので、public static void main()があれば、javaコマンドはこれを実行します。つまり、
public class Point { int x, y; void print () { System.out.println(this.x + ", " + this.y); } public static void main(String args[]) { Point pt1 = new Point(); //自分自身からインスタンスを作る Point pt2 = new Point(); //自分自身からもう一つインスタンスを作る pt1.x = 10; pt1.y = 20; pt2.x = - pt1.x; pt2.y = - pt1.y; pt1.print(); pt2.print(); } }
これで、java Pointコマンドで、テストすることができます。 やっていることは、少しややこしいので、しっかり確認してください。 クラスメソッドの中で、自分が定義した方法で、インスタンスを作っています。そしてそれを操作しています。
クラスPoint3Dに自分自身をテストするクラスメソッドmainを作ってみよう
public static void main(String args[]) { Point3D pt1 = new Point3D(); //自分自身からインスタンスを作る Point3D pt2 = new Point3D(); //自分自身からもう一つインスタンスを作る pt1.x = 10; pt1.y = 20; pt1.z = 30; pt2.x = - pt1.x; pt2.y = - pt1.y; pt2.z = - pt1.z; pt1.print(); pt2.print(); }
変数とメソッドの定義に使われる修飾子や戻り値の表現は、C言語に似ています。
以下はとても重要です。
クラス変数にはクラス名を指定してピリオドでアクセスします。例えばjava言語には、Mathというクラスが用意されています。MathクラスにはPIというクラス変数が用意されています。なので、Math.PIでアクセスできます。
class MathTest { public static void main (String args[]) { System.out.println(Math.PI); } }
またMath.random()クラスメソッドで乱数が得られます。以前の演習で使いました。
インスタンス変数はインスタンスを作ってからアクセスします。上の例でPointクラスでprint()インスタンスメソッドを作りました。これは、
Point pt1 = new Point(); pt1.print();
としてアクセスできます。クラスメソッドではありませんので、Point.print()ではアクセスできません。インスタンスメソッドだからです。
そのほかの修飾子は、あとで説明しますが、アクセス制御だけ述べておきます。
です。
まずは前回の復習をします。
整数型のインスタンス変数を2個だけ持つクラスです。C言語の構造体に似ています。
public class Point { int x, y; }
先のPoint型のクラスにインスタンスメソッドを1個追加しました。座標を表示するメソッドです。
public class Point { int x, y; void print() { System.out.println(x + ", " + y); } }
クラスからインスタンスを作ることをインスタンス化またはインスタンシエーションと言います。
先のPointクラスとは別の、テスト用クラスTestPointを用意して、その中でPointインスタンスを作るには、以下のようにします。 Pointクラスは別のファイルで定義されていることになりますが、同じディレクトリにそのファイルがあれば、ファイル名を手掛かりに探してくれます。
public class TestPoint { public static void main(String args[]) { Point pt1 = new Point(); Point pt2 = new Point(); } }
配列の時と同じくnewコマンドが使われています。new Point()により、Pointクラスの設計図にしたがって、Point型インスタンスを格納するためのメモリー空間が確保されます。確保されたメモリー領域への参照をPoint型変数に代入しています。ここでは2つのインスタンスを作りました。同じ設計図(クラス)から作られましたが、それぞれ別のものです。
インスタンスのインスタンス変数、インスタンスメソッド(これらを合わせてメンバーと言うこともあります)にアクセスするためには、ピリオドを用います。C言語の構造体と同じです。
pt1とpt2のインスタンス変数に値を代入して、インスタンスメソッドprint()を呼び出すプログラムは以下のようになります。
public class TestPoint { public static void main(String args[]) { Point pt1 = new Point(); Point pt2 = new Point(); pt1.x = 10; pt1.y = 20; pt2.x = - pt1.x; pt2.y = - pt1.y; pt1.print(); pt2.print(); } }
この結果、10, 20と-10, -20が表示されます。
TestPoint3Dというクラスを作って、その中のmain関数で、 先に作ったPoint3Dクラスからインスタンスを2個作り、それぞれの座標を10,20,30と-10,-20,-30に設定し、それぞれの内容をprint()メソッドを呼び出して表示するプログラムを作ってください。 以下のような実行結果が出るようにしてください
クラスからインスタンスを作ることをインスタンス化またはインスタンシエーションと言います。
先のPointクラスとは別の、テスト用クラスTestPointを用意して、その中でPointインスタンスを作るには、以下のようにします。 Pointクラスは別のファイルで定義されていることになりますが、同じディレクトリにそのファイルがあれば、ファイル名を手掛かりに探してくれます。
public class TestPoint { public static void main(String args[]) { Point pt1 = new Point(); Point pt2 = new Point(); } }
配列の時と同じくnewコマンドが使われています。new Point()により、Pointクラスの設計図にしたがって、Point型インスタンスを格納するためのメモリー空間が確保されます。確保されたメモリー領域への参照をPoint型変数に代入しています。ここでは2つのインスタンスを作りました。同じ設計図(クラス)から作られましたが、それぞれ別のものです。
インスタンスのインスタンス変数、インスタンスメソッド(これらを合わせてメンバーと言うこともあります)にアクセスするためには、ピリオドを用います。C言語の構造体と同じです。
pt1とpt2のインスタンス変数に値を代入して、インスタンスメソッドprint()を呼び出すプログラムは以下のようになります。
public class TestPoint { public static void main(String args[]) { Point pt1 = new Point(); Point pt2 = new Point(); pt1.x = 10; pt1.y = 20; pt2.x = - pt1.x; pt2.y = - pt1.y; pt1.print(); pt2.print(); } }
この結果、10, 20と-10, -20が表示されます。
TestPoint3Dというクラスを作って、その中のmain関数で、 先に作ったPoint3Dクラスからインスタンスを2個作り、それぞれの座標を10,20,30と-10,-20,-30に設定し、それぞれの内容をprint()メソッドを呼び出して表示するプログラムを作ってください。 以下のような実行結果が出るようにしてください
整数型のインスタンス変数を2個だけ持つクラスです。C言語の構造体に似ています。
public class Point { int x, y; }
先のPoint型のクラスにインスタンスメソッドを1個追加します。座標を表示するメソッドです。
public class Point { int x, y; void print() { System.out.println(x + ", " + y); } }
まとめです:
mainの引数argsは、Stringの配列で、コマンドラインで起動したとき、 コマンドの後に続けた書いた文字が入っています。 args[0], args[1], args[2] .... をすべてfor-each文で 表示するプログラムを書いてみましょう。 この時、以下のように、args[]の文字をすべてfor-each文で+つけて表示してみましょう。
javac ArgsTest2 cat dog cow fox cat + dog + cow + fox
public class ArgsTest2 { public static void main(String args[]) { boolean isFirstWord = true; for(String s: args) { if(false == isFirstWord) { System.out.print(" + "); } isFirstWord = false; System.out.print(s); } System.out.println(); } }
for-each文は、Cにはなかったです。練習しましょう。
for(型 変数名: 式) {}
int型の4個の配列は、以下のように宣言できます。
int[] array; array = new int[4]
これを1行で表現して、さらに初期値をいれてしまうこともできます。
int[] array = new int[]{1,2,3,4};
int[] array = new int[]{1,2,3,4};
で宣言した配列の中身を、for-each文で順番に表示せよ。ヒントは、
for(int x: array) {}
です。
解答例:
class ArrayTest { public static void main (String args[]) { int[] array = new int[]{1,2,3,4}; for (int x: array) { System.out.println(x); } } }
for文もC言語と同じです。
for(初期設定; 条件; 再設定) {}
10万円を今の1年もの定期預金の年利で複利で運用した時、元利合計が20万円を超えるのは何年後でしょうか? for文で、2項目目に20万円を超える条件を書いて、年数と金額を表示するプログラムを作って調べてみましょう。
for( year = 1; <ここに条件>; year++) {
解答例:
class Kinri { public static void main (String args[]) { double okane=100000; int year; for(year=1; okane < 200000; year++) { okane = okane * 1.002; System.out.println("year = " + year + " okane= " + okane); year++; } } }
break文で直近のループを抜け出せます。上の問題を無限ループにして、break文で書き直してみましょう。
while文もC言語と同じです。
while(条件) {}
上の問題をwhile文で書き直してみましょう。
100点満点のテストの得点から、ABCDの成績を表示するプログラムを作ります。 その準備のために、 0から100までの乱数を10個表示するプログラムを作ります。
public class Score { public static void main (String argv[]) { int i,a; for(i=0;i<10;i++) { a=(int)(Math.random() * 100); System.out.println(a); } } }
Math.random()は、Mathクラスのクラスメソッドであるrandom()を呼び出しているという意味です。 System.out.println()などと同じく、大文字で始まる単語はクラスを表します。
次にこの乱数を100点満点の点数とみなして、成績ABCDを表示するプログラムを書きましょう。 成績の基準は、80点以上がA, 60点以上80点未満がB, 40点以上60点未満がC, 40点未満がDです。 動作例を以下に示します。
解答例1:
public class Score { public static void main(String args[]) { int i,a; char score; for(i=0;i<10;i++){ a= (int)(Math.random() * 100); if(a>=80) score='A'; else if(a>=60) score='B'; else if(a>=40) score='C'; else score='D'; System.out.println(a + " " + score); } } }
解答例2:
public class Score { public static void main (String argv[]) { int i,a; for(i=0;i<10;i++) { a=(int)(Math.random() * 100); System.out.print(a + " "); if(a<40) System.out.println("D"); else if(a<60) System.out.println("C"); else if(a<80) System.out.println("B"); else System.out.println("A"); } } }
制御構造も大半はC言語と同じです。
if文もC言語と同じです。
if (a==0) b=100;
if (a==0) { b=100; }
if (a==0) { b=100; }else{ b=10; }
if (a>100) { }else if (a>10){ }else{ }
演算子はほとんどC言語と同じです。復習しましょう。
変数には算術演算子が使えます。算術演算子はC言語と同じです。
+-*/%
です。%は剰余です。
5 % 2
は1です。
代入演算子は=です。
算術演算子と代入演算子を組み合わせることもできます。
a += 1;
は
a = a + 1;
と同じ意味です。
インクレメント、デクレメント演算子もCと同様です。
a = 1; b = a++;
は、bが1、aが2になります。
a = 1; b = ++a;
は、a, bどちらも2になります。
関係演算子もC言語と同じです。
<, >, <=, >=, ==, !=
論理演算子もC言語と同じです。
&&, ||, !
Javaではbooleanにしか論理演算できないので、&, | だけでもokです。
ビット演算し、シフト演算子もC言語と同じです。
&, |, ^, ~, <<, >>, >>>
1 << 2
は4になります。
キャストもあります。C言語と同じです。
long b=1234; int a = (int)b;
C言語では文字列はただのバイト変数の配列でした。最後の値が0であることで、長さを知ることができる程度です(番兵方式)。 Javaでは文字列は、Stringクラスのインスタンスです。 なんのことかは後の授業で説明しますが、処理をする関数を内包している「構造体Structure」のようなものです。 なので、いろいろな操作が可能です。
文字列は""で括ります。
"Hello Java World!"
printlnできます。
System.out.println("Hello Java World!");
足し算もできます。
System.out.println("This is " + "a test.");
変数にも代入できます。変数の種類はStringです。オブジェクト指向の用語で説明すると、Stringクラスのインスタンスとしてworldを定義したということです。クラスは設計図、雛形、金型のようなもので、インスタンスはそれから作成された実体のようなものです。
String world = "Hello Java World!";
最初に作ったHello.javaプログラムを、String変数 worldという変数に代入してから表示するプログラムに書き換えてみましょう。
解答例:
class Hello { public static void main (String args[]) { String world = "hello java world!"; System.out.println(world); } }
ヒント
class ArgsTest { public static void main (String args[]) { System.out.println(args[0]); } }
できてしまった人は以下をお願いします。
このプログラムで、引数が2個未満の場合はエラーになります。 2個未満の場合には、2個引数を描いてくださいというメッセージを出すよう変更しましょう。 .length関数でargsの長さを知ることができます。 if文はC言語と同じです。
if(args.length < 2) { } else { }
というように書けます。
C言語では小規模な配列を使う場合、静的に確保した配列をよく使っていたと思います。 Javaでは、システムからメモリー確保して動的に確保した配列を使うのが一般的です。 C言語でもmalloc()関数でメモリーを確保したことがあると思います。 例えばint型の変数3個分のメモリを確保して、それをint型を示すポインターに入れて、配列として使いました。
//C言語での例です: int *p; *p = (int *)malloc(sizeof(int)*3);
Javaでも同じことをやります。 システムにお願いして、必要な量の配列を格納するメモリー領域を確保してもらいます。そのコマンドがnewです。
まずは配列の変数を定義して、次にnewコマンドで必要なメモリー領域を確保して、それが返すメモリーアドレス(に相当する値)を配列の変数に入れます。メモリーアドレスに相当する数値は、C言語ではポインターと言いましたが、Javaでは参照と言います。
int[] x; (配列を参照する変数を定義する) x = new int[3]; (int3個ぶんのメモリー領域をnewコマンドで取得して参照をxに代入する)
こうすると、プログラムの中からx[0]=1;とかx[2]=x[0];などと操作してこの配列を利用できます。
1行でまとめて書くこともあります。
int[] x = new int[3];
演習3
要素が100個のintの配列x[0]からx[99]を作って、それに1,2,3,4....,100という数字を入れて、さらにそれらをprintlnで表示するプログラムを作りましょう。先ほどのVartest.javaを改造して作ってください。for文で値を入れて、for文で表示してください。for文の使い方はC言語と同一です。
ヒント:
class Vartest { public static void main (String args[]) { //配列を定義します。 //(略) //for文で値を入れます for(int i=0; i<100; i++) { //(略) } //for文で表示します for(int i=0; i<100; i++) { //(略) } }
C言語と違い、整数型のサイズが明確に決められました。char型は、C言語では1バイトでしたが、Javaでは1文字を表します。なので、コードによって1バイトだったり、多バイトだったりします。C言語では論理型がないので、charやintで代用していました。0とか1を代入してました。Javaでは専用のboolean型が用意されました。
先に作ったHello.javaを参考にVartest.javaというプログラムを作りましょう。 以下では、byte型変数を定義して、それを表示しています。 変数名は変えても良いです。 printlnの中では、文字列を連結しています。Javaでは文字列を+で連結できます。
class Vartest { public static void main (String args[]) { int x = 42; System.out.println("byte value x =" + x); } }
これをもとに、short, int, long, char, float, double booleanの変数を全て追加して表示をしてください。intとcharを追加するなら、以下のようにします。変数名と代入する値は好きなものを使ってください。char型は漢字も試してください。ただしchar型は、1文字だけです。
class Vartest { public static void main (String args[]) { byte x= 42; int x1= 123456; char name = '椎'; System.out.println("byte value x =" + x); System.out.println("int value x1 =" + x1); System.out.println("char value name =" + name); } }
解答例:
class Vartest { public static void main (String args[]) { byte x_byte = 42; int x_int = 12345; short x_short = 123; long x_long = 12345678; char x_char = '椎'; float x_float = 123.4f; double x_double = 3.14d; boolean x_boolean = true; System.out.println("byte value x_byte = " + x_byte); System.out.println("short value x_short = " + x_short); System.out.println("int value x_int = " + x_int); System.out.println("long value x_long = " + x_long); System.out.println("char value x_char = " + x_char); System.out.println("float value x_float = " + x_float); System.out.println("double value x_double = " + x_double); System.out.println("boolean value x_boolean = " + x_boolean); } }
以下のように、整数型の変数に文字を代入して値を表示すると、文字コードが表示できる。 あなたのイニシャルを表す英文字の文字コードを表示するプログラムを作成しなさい。また、あなたの氏名の最初の文字(漢字やひらがな)についても調べなさい。
int myInitialCode1 = 'S', myInitialCode2 = '椎'; System.out.println(myInitialCode1); System.out.println(myInitialCode2);
授業の最後の方で紹介する,Swingというフレームワークを使ってウィンドウを出してみます.
import javax.swing.JFrame; public class SimpleWindow { public static void main(String argv[]) { JFrame f = new JFrame("私が作った最初の窓"); f.setSize(200,100); f.setVisible(true); } }
これをSimpleWindow.javaという名前で保存して、
javac SimpleWindow.java java SimpleWindow
とタイプしてコンパイル/実行します。 このプログラムは,ウィンドウのクローズボタンを押しても終了しません. プログラムを停止するには,ターミナルでコントロール-cを押します.
class Hello { public static void main (String args[]) { System.out.println("hello java world!"); } }
$ ls Hello.java $ cat Hello.java class Hello { public static void main (String args[]) { System.out.println("hello java world!"); } }
今は、Hello.javaファイルが一つしかありません。これをコンパイルします。
$ javac Hello.java (コンパイルする) コンパイルに成功するとHello.classというファイルができているはずです。lsコマンドで確認します。 $ ls Hello.class Hello.java
これはjavaコマンドで動作します。javaはインタープリータです。
$ java Hello (実行する。.javaなどの拡張子は不要) hello java world! (結果)
http://docs.oracle.com/javase/jp/8/docs/api/index.html
http://www.amazon.co.jp/dp/4883732258/
前半はこの内容で進めますので、手元にあると便利です。
授業の内容を入れておくフォルダを作ってください。Documentsの中にjavaというようなフォルダを作ると良いです。
以下のアプリケーションで、授業開始に出席表明してもらいます。皆さんがクリックし終わったら、締め切ります。それまでにクリックできない人は遅刻とします。
/home/isstaff/siio/Public/Drop Box/.に提出してください。ターミナル.appからなら
cp 123456siioitiro.zip /home/isstaff/siio/Public/Drop\ Boxとしてください。ファインダーからなら、メニューから「移動」「フォルダへ移動...」を選んで 以下のように入力して、移動ボタンを押して、そこに現れるドロップボックスホルダに、ドラッグアンドドロップしてください。
提出は任意です.もし良いレポートを提出いただけたら出席点の加算に使用します.
メールの標題は「ヒューマンインタフェースレポート: 17205XX」としてください。数字部分は出席番号です。 提出いただいた方はこのページでお知らせします。提出してしばらく経つのに、 自分の番号がなかなか表示されない場合は,受付されていないかもしれません.もう一度催促してください (提出を確認出来るよう締め切りより早めに提出していただくことをお勧めします)。
学部「ヒューマンインタフェース」は出席重視の授業です.そのため70%以上出席お願いします. 授業回数が13回ですので,欠席が3回を超えた場合は単位が出ません. 以下に授業全体の欠席状況を示す予定です。 欠席回数は成績に大きく影響しますので、間違いありましたら至急お知らせください.
下のリンク先のソースコードをコンパイルして、応答速度を図るプロログラムを作ってください。これを使って、みなさんの応答速度を図って、次回(2019年5月16日)の小テスト用紙(A5サイズ)で報告してください。
http://lab.siio.jp/index.php?CSL11HCI#k497ebbd
http://www.amazon.co.jp/dp/4781912605/
(授業開始直前や直後に差し替えされている可能性があります。)
このページについてのお問い合わせはsiio@is.ocha.ac.jpまで。