目次 | 索引 |
---|---|
データ型 ( data type ) とは、データの種類のことです。 これまでに、整数、配列、およびクラスの3種類のデータ型を扱ってきました。 Java言語には、この他のデータ型も用意されています。
Java言語のデータ型は、まず基本データ型と参照データ型の2つに大きく分類されます。 基本データ型 ( primitive data type ) には、整数型、浮動小数点数型、論理型、および文字型があります。 参照データ型 ( reference data type ) には、クラス型と配列型があります。 以下は基本データ型の詳細です。
種類 | 型名 | ビット | 説明 |
---|---|---|---|
整数型 | byte |
8 | -27(-128)〜27- 1(127) |
整数型 | short |
16 | -215(-32768)〜215- 1(32767) |
整数型 | int |
32 | -231〜231- 1(9桁程度) |
整数型 | long |
64 | -263〜263- 1(18桁程度) |
浮動小数点数型 | float |
32 | 指数+38〜-45, 有効桁数7桁程度 |
浮動小数点数型 | double |
64 | 指数+308〜-324, 有効桁数14桁程度 |
論理型 | boolean |
- | trueまたはfalse |
文字型 | char |
16 | \u0000(0)〜\uFFFF(65535) |
コンピュータのデータの単位は ビット ( bit ) であることを思い出してください。 ただし、これは理論上の話です。 現実のコンピュータ・システムは、 バイト ( byte ) を単位としています。 1バイトは8ビットです。 基本データ型が8ビット単位であるのは、ここに理由があります。
整数を扱う場合、普通は
int
型を用います。
ただし、
int
型は9桁程度が限界であり、これを超えますと意味のない計算をしてしまいます。
int
型の範囲を超えるような大きい数を扱うときに、
long
型を用います。
浮動小数点数
(
floating point number
)
とは、小数点をずらすことによって、非常に大きな数や非常に小さな数も表現できるようにした小数のことです。
浮動小数点数を扱う場合、普通は
double
型を用います。
限られたビット数で表現する以上、小数点をずらす桁数には限度がありますし、小数の精度にも限界があります。
論理型
(
logical type
)
とは、真理値を表わすデータ型です。
ここで
真理値
(
truth value
)
とは、真を表す記号 true と偽を表す記号 false のことだと思ってください。
Java では、型名
boolean
で論理型を表わします。
値が論理型である式を、
ブール式
(
Boolean expression
)
とよびます。
これまで「条件が成り立つ」、「条件が成り立たない」と言ってきたことは、正確にはブール式の値が true になること、false になることです。
Javaは、文字(
char
型)を1バイトではなく2バイトで表現します。
これは、英数字だけではなく、漢字なども文字として扱おうという設計です。
なお、ちょうど1バイトで表現されるデータ型として、バイト(
byte
)が用意されています。
文字は、内部では整数として処理されます。 この、文字から整数への対応を 文字符号 ( character code ) と呼びます。 Javaの採用している文字符号は、 Unicode と呼ばれる体系です。 Unicodeは ASCII という体系の拡張になっています。 主な文字のASCII符号は次の通りです。
制御文字 | 水平タブ | 改行 | 復帰 | スペース |
---|---|---|---|---|
表示 | '\t' | '\n' | '\r' | ' ' |
符号 | 9 | 10 | 13 | 32 |
文字 | ! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
符号 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
文字 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | : | ; | < | = | > | ? |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
符号 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
文字 | @ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
符号 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
文字 | P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
符号 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
文字 | ` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
符号 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
文字 | p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
符号 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 |
プログラムの中で文字を表す場合、その文字をシングルクオート(
'
)で囲みます。
ただし、シングルクオート自身、およびダブルクオート(
"
)、バックスラッシュ(
\
)については、それぞれ
'\''
,
'\"'
,
'\\'
とします。
以前、メソッドにはインスタンスメソッドとクラスメソッドがあると言いました。 これまではクラスメソッドのみを使ってきましたが、Javaらしいプログラムではインスタンスメソッドのほうがよく用いられます。 クラスメソッドと比較しながら、インスタンスメソッドについて説明します。
前回、以下のようなプログラムを紹介しました。
/* 1*/ class Time { /* 2*/ int hour, minute; /* 3*/ }
/* 1*/ class TimeTest5 { /* 2*/ public static void main (String[] args) { /* 3*/ Time x = new Time(); /* 4*/ setHour(x, 14); /* 5*/ setMinute(x, 45); /* 6*/ System.out.println(getHour(x) + ":" + getMinute(x)); /* 7*/ setMinute(x, 30); /* 8*/ System.out.println(getHour(x) + ":" + getMinute(x)); /* 9*/ } /* 10*/ static int getHour (Time t) { /* 11*/ return t.hour; /* 12*/ } /* 13*/ static int getMinute (Time t) { /* 14*/ return t.minute; /* 15*/ } /* 16*/ static void setHour (Time t, int hour) { /* 17*/ t.hour = hour; /* 18*/ } /* 19*/ static void setMinute (Time t, int minute) { /* 20*/ t.minute = minute; /* 21*/ } /* 22*/ }
これを、インスタンスメソッドを用いて書きなおしますと、次のようになります。
/* 1*/ class Time { /* 2*/ int hour, minute; /* 3*/ int getHour () { /* 4*/ return this.hour; /* 5*/ } /* 6*/ int getMinute () { /* 7*/ return this.minute; /* 8*/ } /* 9*/ void setHour (int hour) { /* 10*/ this.hour = hour; /* 11*/ } /* 12*/ void setMinute (int minute) { /* 13*/ this.minute = minute; /* 14*/ } /* 15*/ }
/* 1*/ class TimeTest5 { /* 2*/ public static void main (String[] args) { /* 3*/ Time x = new Time(); /* 4*/ x.setHour(14); /* 5*/ x.setMinute(45); /* 6*/ System.out.println(x.getHour() + ":" + x.getMinute()); /* 7*/ x.setMinute(30); /* 8*/ System.out.println(x.getHour() + ":" + x.getMinute()); /* 9*/ } /* 10*/ }
b00a001@AsiaA1:~/java% java TimeTest5 14:45 14:30 b00a001@AsiaA1:~/java%
まず、メソッド定義を実行プログラム(
main
)には並べて書かず、フィールド定義に並べて書きます。
レコード型としてのクラスはフィールドとコンストラクタを定義しますが、一般のクラスはさらにメソッドも定義します。
メソッドは、実行プログラムよりもデータ(インスタンス)に強く結び付くと考えます。
次に、キーワード
static
を取り除きます。
メソッド定義で
static
と書くとクラスメソッド、書かないとインスタンスメソッドになります。
メソッド呼出しの形も変えます。 値を返さないインスタンスメソッドを呼び出すには、文
instance.methodname(argument, ...);
を用います。 ここで instance は、インスタンスを値とする式です。 例えば、インスタンス(への参照)が格納された変数などです。 値を返すインスタンスメソッドを呼び出すには、式
instance.methodname(argument, ...)
を用います。 なお、括弧がなければインスタンスのフィールドからデータを取り出す形になります。
この式
instance
は、メソッド呼出しの実引数としての役割を果たします。
この実引数に対応する仮引数は、メソッド定義でのキーワード
this
です。
メソッド呼出しの際、
this
にはインスタンス
instance
への参照がコピーされます。
インスタンスメソッドとは、引数の中からインスタンスを一つ選び、それを特別扱いしたものと考えてください。
特別扱いされたインスタンスは、実引数としては、括弧の中ではなく、メソッド名の左に書かれます。
仮引数としては、括弧の中では定義されず、キーワード
this
で表されます。
この、引数の一つのインスタンスを特別扱いすることは、
メッセージ受渡しモデル
(
message-passing model
)
に基づいています。
これは、データ(インスタンス)がメッセージを受け取ると、それに応じて操作(メソッド)が引き起こされるという考え方です。
Javaでのメッセージは、メソッド名のことだと思ってください。
インスタンスにメッセージを送りますと、そのインスタンスのクラスで定義されたメソッドが起動されるということです。
メッセージ受渡しモデルに従いますと、上記のメソッド呼出しは、インスタンス
instance
にメッセージ
methodname
(
argument
,
...
)
を送ることに相当します。
インスタンスメソッドにできて、クラスメソッドにできないことのひとつに、メソッド定義で
this
参照を用いることがあげられます。
this
参照は、インスタンスメソッドの呼出しのときにメッセージを受け取ったインスタンスを指します。
クラスメソッドでは、メッセージを受け取るインスタンスが存在しませんので、
this
参照が使えないのです。
これまで説明した通り、変数は宣言すれば使えます。 しかし、いつまでも使い続けられるわけではありません。 例えば、メソッド定義
static void printStars (int m) { int i; for (i = 0; i < m; i++) { System.out.print("*"); } }
での変数
i
は、メソッド呼出しの際に用意されます。
しかし、この呼出しが終了しますと、変数
i
は使えなくなります。
このような変数は
局所変数
(
local variable
)
とよばれます。
データを局所変数に格納しても、他のメソッドからはそのデータは利用できません。 複数のメソッドの間でデータを共有するには、大域変数というものを用います。 大域変数 ( global variable ) とは、プログラムのどこからでも使える変数です。 あるメソッドで大域変数にデータを格納し、他のメソッドでそれを取り出すことができます。
実は、Javaには大域変数は用意されていません。 これは、クラス変数というもので代用します。 クラス変数 ( class variable ) とは、クラスに割り当てられる変数と考えてください。 クラス変数と対照的なのがインスタンス変数(すなわちフィールド)です。 クラスのインスタンスを生成しますと、インスタンスごとにインスタンス変数が用意されます。 一方、クラス変数は、インスタンスをいくら生成しても、クラスにひとつだけ用意されます。 次の図は、クラス変数とインスタンス変数のイメージです。
クラス変数の宣言は、フィールドと同じように行います。
フィールドとの違いは、キーワード
static
を書くところです。
クラス class のクラス変数 variable にアクセスするには、 class . variable と書きます。 ただし、同じクラスからアクセスする場合は、 variable だけで十分です。
次のプログラムは、出勤時刻に関して遅刻の回数を数えるものです。
Attendance.javaの3行目で、クラス変数
lateCount
を用意します。
10行目では、単に
lateCount
でアクセスできますが、AttendanceTest.javaの10行目では
Attendace.lateCount
と指定します。
/* 1*/ class Attendance { /* 2*/ int hour, minute; /* 3*/ static int lateCount = 0; /* 4*/ Attendance (int hour, int minute) { /* 5*/ this.hour = hour; /* 6*/ this.minute = minute; /* 7*/ } /* 8*/ void checkLate () { /* 9*/ if (540 < 60 * this.hour + this.minute) { /* 10*/ lateCount++; /* 11*/ } /* 12*/ } /* 13*/ }
/* 1*/ class AttendanceTest { /* 2*/ public static void main (String[] args) { /* 3*/ int i; /* 4*/ Attendance[] atts = {new Attendance(8, 55), /* 5*/ new Attendance(9, 10), /* 6*/ new Attendance(9, 5)}; /* 7*/ for (i = 0; i < atts.length; i++) { /* 8*/ atts[i].checkLate(); /* 9*/ } /* 10*/ System.out.println(Attendance.lateCount); /* 11*/ } /* 12*/ }
b00a001@AsiaA1:~/java% java AttendanceTest 2 b00a001@AsiaA1:~/java%
大域変数を用いて定数を表すことがよくあります。 定数 ( constant ) とは、常に変わらない値のことです。 プログラムに定数を直接書きますと、それが何を表しているのか分かりにくいものです。 そこで、大域変数に定数を代入しておき、定数の代りに変数名を書きます。 定数に分かりやすい名前をつけ、プログラムを読みやすくするのです。
定数を表す変数へは、新たな代入が行われないようにしなくてはいけません。
変数を宣言するときに、キーワード
final
を書きますと、値の変更が禁止されます。
これによって、どの変数が定数を表すのかが明確になります。
上記のプログラムでは、Attendance.java の9行目の条件
540 < 60 * this.hour + this.minute
の
540
が何を表しているのかが分かりにくいでした。
これは始業時刻9:00の絶対時刻(分)です。
定数を
final static int OPENINGHOUR = 9; final static int OPENINGMINUTE = 0;
と定め、条件を
60 * OPENINGHOUR + OPENINGMINUTE < 60 * this.hour + this.minute
と書きますと、出勤時刻が始業時刻以後ならば…と読めるわけです。
/* 1*/ class Attendance { /* 2*/ int hour, minute; /* 3*/ static int lateCount = 0; /* 4*/ final static int OPENINGHOUR = 9; /* 5*/ final static int OPENINGMINUTE = 0; /* 6*/ Attendance (int hour, int minute) { /* 7*/ this.hour = hour; /* 8*/ this.minute = minute; /* 9*/ } /* 10*/ void checkLate () { /* 11*/ if (60 * OPENINGHOUR + OPENINGMINUTE /* 12*/ < 60 * this.hour + this.minute) { /* 13*/ lateCount++; /* 14*/ } /* 15*/ } /* 16*/ }
インスタンスメソッドの例として、アニメーションのアプレットを作成します。 アニメーションは、以下のような12個のランプを次々とフラッシュさせるものです。 ちゃんとしたアニメーションを実現するには、高度なプログラミングが必要なのですが、ここではなるべく簡単な方法で行います。
アニメーションのアプレットのパターンは次の通りです。
import java.applet.*; import java.awt.*; public class program name extends Applet { variable declaration and initialization ... public void paint (Graphics g) { update graphics ... try { Thread.sleep(msec); } catch (InterruptedException e) { } repaint(); } }
まず、変数の宣言と初期化は、今までと違って
paint
ブロックの外側で行います。
paint
ブロックの内側では、グラフィックスの更新処理を行います。
ここは、何度も繰り返し実行されます。
更新処理の後、ある一定の時間、実行を停止します。
パターン通りに書きますと、実行が
msec
ミリ秒停止します。
最後の
repaint()
で、アニメーションが続行されます。
ファイルLamp.javaでは、ランプの位置を格納するために、クラス
Lamp
を定義します。
フィールド
posX
と
posY
にランプの座標を格納します。
コンストラクタも定義します。
ファイルLamp.javaでは、インスタンスメソッド
light
を定義します。
これは、ランプを点灯させるものです。
引数は、アプレットに特有の、
Graphics
の
g
のみです。
このメソッドは値を返しませんので、
void
と指定します。
メソッド定義の要点は、ランプの座標に白く塗り潰された円を描くことです。
なお、アプレットに関係するクラスの場合、次の1〜2行目を忘れないでください。
/* 1*/ import java.applet.*; /* 2*/ import java.awt.*; /* 3*/ /* 4*/ class Lamp { /* 5*/ int posX, posY; /* 6*/ Lamp (int posX, int posY) { /* 7*/ this.posX = posX; /* 8*/ this.posY = posY; /* 9*/ } /* 10*/ void light (Graphics g) { /* 11*/ g.setColor(Color.white); /* 12*/ g.fillOval(this.posX, this.posY, 10, 10); /* 13*/ } /* 14*/ }
ファイルLampMain.javaでは、
paint
ブロックの外側でアニメーションの初期化を行います(5行目から11行目)。
アルゴリズムは次のようになります。
プログラムは以下のようになります。
/* 1*/ import java.applet.*; /* 2*/ import java.awt.*; /* 3*/ /* 4*/ public class LampMain extends Applet { /* 5*/ int index = 0; /* 6*/ Lamp[] lamps = {new Lamp(95, 15), new Lamp(135, 25), /* 7*/ new Lamp(165, 55), new Lamp(175, 95), /* 8*/ new Lamp(165, 135), new Lamp(135, 165), /* 9*/ new Lamp(95, 175), new Lamp(55, 165), /* 10*/ new Lamp(25, 135), new Lamp(15, 95), /* 11*/ new Lamp(25, 55), new Lamp(55, 25)}; /* 12*/ public void paint (Graphics g) { /* 13*/ g.setColor(Color.black); /* 14*/ g.fillRect(0, 0, 200, 200); /* 15*/ lamps[index].light(g); /* 16*/ index++; /* 17*/ if (index >= lamps.length) { /* 18*/ index = 0; /* 19*/ } /* 20*/ try { /* 21*/ Thread.sleep(80); /* 22*/ } catch (InterruptedException e) { /* 23*/ } /* 24*/ repaint(); /* 25*/ } /* 26*/ }
ピンポン球が壁に跳ね返るアニメーションのアプレットを作成します。 壁は長方形の辺とし、その内側をピンポン球が動くものとします。
ピンポン球には動く方向が定まっており、壁に当たるまではその方向に動き続けます。 ここで、動く方向とは単位時間後の位置のずれと考えます。 つまり、座標ごとに今の位置と方向を足せば、次の位置になるわけです。
縦の( y 軸に平行な)壁に当たった場合は、横方向( x 軸方向)に動けませんので、動く方向の x 座標の正負が反転します。 横の( x 軸に平行な)壁に当たった場合は、縦方向( y 軸方向)に動けませんので、動く方向の y 座標の正負が反転します。 壁に当たることの判定は、次の位置を計算し、それが長方形からはみ出す場合とします。 その際に、ピンポン球の大きさも算入する必要があります。
ピンポン球の大きさは縦横10ピクセルとし、長方形は幅300ピクセル、高さ200ピクセルとします。
ファイルPingPong.javaでは、ピンポン球の位置と動く方向を格納するために、クラス
PingPong
を定義します。
フィールド
posX
と
posY
には、位置の
x
座標と
y
座標を格納します。
フィールド
stepX
と
stepY
には、方向の
x
座標と
y
座標を格納します。
コンストラクタは、引数が位置の
x
座標、
y
座標、方向の
x
座標、
y
座標の順になるように定義します。
ファイルPingPong.javaでは、インスタンスメソッド
nextX
を定義します。
これは、次の位置の
x
座標を返すものです。
引数は、ありません。
このメソッドは整数を返しますので、
int
と指定します。
メソッド定義の要点は、位置の
x
座標
this.
posX
と方向の
x
座標
this.
stepX
の和を返すことです。
y
座標についてのインスタンスメソッド
nextY
も同様に定義します。
ファイルPingPong.javaでは、インスタンスメソッド
turnX
を定義します。
これは、方向の
x
座標の正負を反転させるものです。
引数は、ありません。
このメソッドは値を返しませんので、
void
と指定します。
メソッド定義の要点は、フィールド
this.
stepX
に、その値のマイナスを格納することです。
y
座標についてのインスタンスメソッド
turnY
も同様に定義します。
ファイルPingPong.javaでは、インスタンスメソッド
move
を定義します。
これは、ピンポン球の位置を変更して、その位置にピンポン球を描くものです。
引数は、
Graphics
の
g
です。
このメソッドは値を返しませんので、
void
と指定します。
メソッド定義の要点は、フィールド
this.
posX
の値を
this.
stepX
だけ増加させ、フィールド
this.
posY
の値を
this.
stepY
だけ増加させ、左上の座標が (
this.
posX
,
this.
posY
) で縦横が10ピクセルの白く塗り潰された円を描くことです。
ファイルPingPongMain.javaでは、アニメーションの初期化を行います。 これは、
PingPong pp = new PingPong(50, 100, 10, 10);
とします。
アルゴリズムは次のようにします。
.
nextX
()
が0未満か290超ならば、{
()
を送る。
.
nextY
()
が0未満か190超ならば、{
()
を送る。
(
g
)
を送る。
このアルゴリズムをプログラムにしてください。
余力のある人は、アニメーションの初期化を以下のように行って、5つのピンポン球を動かしてください。
PingPong[] pps = {new PingPong(50, 100, 10, 10), new PingPong(60, 110, 10, 10), new PingPong(70, 120, 10, 10), new PingPong(80, 130, 10, 10), new PingPong(90, 140, 10, 10)};
なお、ピンポン球同士の衝突は考えなくても構いません。
今日の演習11に従ってJavaプログラムを作成し、そのプログラムをkonishi@twcu.ac.jpあてにメールで提出してください。 メールには、学生番号、氏名、科目名、授業日(12/4)を明記してください。