作成した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まで。