目次 | 索引 |
---|---|
データ型 ( 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*/ }
b04a001@AsiaA1:~/java% java TimeTest5 14:45 14:30 b04a001@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*/ }
b04a001@AsiaA1:~/java% java AttendanceTest 2 b04a001@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*/ }
前回は、以下のようなプログラムで、25分遅れて運転されている電車の発車時刻を計算しました。
/* 1*/ class Departure { /* 2*/ int hour, minute; /* 3*/ Departure (int hour, int minute) { /* 4*/ this.hour = hour; /* 5*/ this.minute = minute; /* 6*/ } /* 7*/ }
/* 1*/ // 円記号対策のコメント /* 2*/ class DepartureMain { /* 3*/ public static void main (String[] args) { /* 4*/ int i, late = 25; /* 5*/ Departure[] deps = {new Departure(8, 30), /* 6*/ new Departure(8, 40), /* 7*/ new Departure(8, 50), /* 8*/ new Departure(9, 0), /* 9*/ new Departure(9, 10)}; /* 10*/ System.out.println("Usual\tToday"); /* 11*/ for (i = 0; i < deps.length; i++) { /* 12*/ show(deps[i]); /* 13*/ System.out.print("\t"); /* 14*/ delay(deps[i], late); /* 15*/ show(deps[i]); /* 16*/ System.out.println(); /* 17*/ } /* 18*/ } /* 19*/ static void show (Departure d) { /* 20*/ System.out.print(d.hour + ":"); /* 21*/ if (d.minute < 10) { /* 22*/ System.out.print("0"); /* 23*/ } /* 24*/ System.out.print(d.minute); /* 25*/ } /* 26*/ static void delay (Departure d, int minute) { /* 27*/ d.hour = d.hour + (d.minute + minute) / 60; /* 28*/ d.minute = (d.minute + minute) % 60; /* 29*/ } /* 30*/ }
b04a001@AsiaA1:~/java% java DepartureMain Usual Today 8:30 8:55 8:40 9:05 8:50 9:15 9:00 9:25 9:10 9:35 b04a001@AsiaA1:~/java%
これを、インスタンスメソッドを用いて書き直しますと、次のようになります。
/* 1*/ // 円記号対策のコメント /* 2*/ class Departure { /* 3*/ int hour, minute; /* 4*/ Departure (int hour, int minute) { /* 5*/ this.hour = hour; /* 6*/ this.minute = minute; /* 7*/ } /* 8*/ void show () { /* 9*/ System.out.print(this.hour + ":"); /* 10*/ if (this.minute < 10) { /* 11*/ System.out.print("0"); /* 12*/ } /* 13*/ System.out.print(this.minute); /* 14*/ } /* 15*/ void delay (int minute) { /* 16*/ this.hour = this.hour + (this.minute + minute) / 60; /* 17*/ this.minute = (this.minute + minute) % 60; /* 18*/ } /* 19*/ }
/* 1*/ // 円記号対策のコメント /* 2*/ class DepartureMain { /* 3*/ public static void main (String[] args) { /* 4*/ int i, late = 25; /* 5*/ Departure[] deps = {new Departure(8, 30), /* 6*/ new Departure(8, 40), /* 7*/ new Departure(8, 50), /* 8*/ new Departure(9, 0), /* 9*/ new Departure(9, 10)}; /* 10*/ System.out.println("Usual\tToday"); /* 11*/ for (i = 0; i < deps.length; i++) { /* 12*/ deps[i].show(); /* 13*/ System.out.print("\t"); /* 14*/ deps[i].delay(late); /* 15*/ deps[i].show(); /* 16*/ System.out.println(); /* 17*/ } /* 18*/ } /* 19*/ }
12行目は、 i 番目の発車時刻を表すインスタンス deps [ i ] に、表示するようにとメッセージ show () を送るという意味です。 また、14行目は、インスタンス deps [ i ] に、発車時刻を遅らせるようにとメッセージ delay ( late ) を送るという意味です。
ある電気店で、携帯電話のキャンペーンを行っているとします。 このキャンペーンとは、その店で契約すると、基本料金の課金開始日を翌々月の1日に変更するというものです。 これまでに、次の5つの契約があったとします。 変更前の課金開始日を格納した後これらを変更するプログラムを作成してください。
変更前 | 変更後 |
---|---|
2003-10-05 | 2003-12-01 |
2003-10-25 | 2003-12-01 |
2003-11-10 | 2004-01-01 |
2003-12-15 | 2004-02-01 |
2004-01-20 | 2004-03-01 |
ファイルBasicCharge.javaでは、基本料金の課金開始日を格納するために、クラス
BasicCharge
を定義します。
フィールド
year
には年を、
month
には月を、
day
には日を格納します。
コンストラクタは、引数が
year
,
month
,
day
の順になるように定義します。
ファイルBasicCharge.javaでは、インスタンスメソッド
change
を定義します。
これは、課金開始日を翌々月の1日に変更するものです。
引数はありません。
このメソッドは値を返しませんので、
void
と指定します。
メソッド定義の要点は、翌々月が13月や14月のとき、これを翌年の1月や2月にすることです。
ファイルBasicCharge.javaでは、インスタンスメソッド
show
を定義します。
これは、課金開始日を"2003-10-05"という形式で表示するものです。
引数はありません。
このメソッドは値を返しませんので、
void
と指定します。
メソッド定義の要点は、月や日が10未満ならば、文字列"0"を追加して出力することです。
ファイルBasicChargeMain.javaでは、次のようにコンストラクタを呼び出して、配列 bcs にすべての課金開始日を格納します。
BasicCharge[] bcs = {new BasicCharge(2003, 10, 5), new BasicCharge(2003, 10, 25), new BasicCharge(2003, 11, 10), new BasicCharge(2003, 12, 15), new BasicCharge(2004, 1, 20)};
アルゴリズムは次のようにします。
BasicCharge
の配列
bcs
を宣言し、上記の要領で初期化する。
このアルゴリズムをプログラムにしてください。
b04a001@AsiaA1:~/java% java BasicCharge Before After 2003-10-05 2003-12-01 2003-10-25 2003-12-01 2003-11-10 2004-01-01 2003-12-15 2004-02-01 2004-01-20 2004-03-01 b04a001@AsiaA1:~/java%
余力のある人は、
今日の演習10に従ってJavaプログラムを作成し、そのプログラムをkonishi@twcu.ac.jpあてにメールで提出してください。 メールには、学生番号、氏名、科目名、授業日(6/25)を明記してください。