データ型 ( data type ) とは、データの種類のことです。 これまでに、整数と実数の2種類のデータを扱ってきました。 また、配列というデータも利用しました。 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) |
コンピュータのデータは、究極的には0と1です。 この0と1を、 ビット ( bit ) と呼びます。 8桁のビットを バイト ( byte ) と呼びます。 現在のコンピュータは、バイトを基本単位としています。 基本データ型が8ビット単位であるのは、ここに理由があります。
整数を扱う場合、普通は
int
型を用います。
ただし、
int
型は9桁程度が限界であり、これを超えると意味のない計算をしてしまいます。
int
型の範囲を超えるような大きい数を扱うときに、
long
型を用います。
今まで、実数と呼んできたものは、正確に言うと浮動小数点数です。
浮動小数点数
(
floating point number
)
とは、小数点をずらすことによって、非常に大きな数や非常に小さな数も表現できるようにした実数のことです。
浮動小数点数を扱う場合、普通は
double
型を用います。
限られたビット数で表現する以上、小数点をずらす桁数には限度がありますし、小数の精度にも限界があります。
Javaには、物事の真偽を表すデータもあります。 正しいことや条件が成り立つことが真で、記号 true で表されます。 間違っていることや条件が成り立たないことが偽で、記号 false で表されます。 この true と false を 真理値 ( truth value ) と呼びます。
論理型
(
logical type
)
とは、真理値を表すデータ型です。
Javaでは、
boolean
型が論理型です。
値が論理型である式を、
ブール式
(
Boolean expression
)
と呼びます。
これまで「条件が成り立つ」とか「条件が成り立たない」と言ってきたことは、正確には、ブール式の値が true や false になることです。
Javaにとっては、文字も立派なデータです。 しかも、アルファベットだけでなく、漢字などもデータとして扱えます。
もし、文字を1バイトで表現すると、256種類が限界となります。
2バイトなら、65536種類の文字が表現可能です。
Javaは、文字(
char
型)を1バイトではなく2バイトで表現します。
なお、ちょうど1バイトで表現されるデータ型として、バイト(
byte
)が用意されています。
文字は、コンピュータの中では整数として処理されます。 この、文字から整数への対応を 文字符号 ( character code ) と呼びます。
Javaが採用している文字符号はUnicodeです。 このUnicodeを理解するには、その前にASCIIを理解する必要があります。 ASCII は、アメリカで制定された文字符号です。 ASCIIでは、数字、アルファベット、記号などに符号が割り当てられています。 そして、 Unicode は、ASCIIを元にして、世界中の文字を追加した文字符号です。 Unicodeでは、漢字などにも符号が割り当てられています。
主な文字のASCII符号は次の通りです。
文字 | 符号 | 文字 | 符号 | 文字 | 符号 | 文字 | 符号 | 文字 | 符号 | 文字 | 符号 | |||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 48 | @ | 64 | P | 80 | ` | 96 | p | 112 | |||||||
! | 33 | 1 | 49 | A | 65 | Q | 81 | a | 97 | q | 113 | |||||
" | 34 | 2 | 50 | B | 66 | R | 82 | b | 98 | r | 114 | |||||
# | 35 | 3 | 51 | C | 67 | S | 83 | c | 99 | s | 115 | |||||
$ | 36 | 4 | 52 | D | 68 | T | 84 | d | 100 | t | 116 | |||||
% | 37 | 5 | 53 | E | 69 | U | 85 | e | 101 | u | 117 | |||||
& | 38 | 6 | 54 | F | 70 | V | 86 | f | 102 | v | 118 | |||||
' | 39 | 7 | 55 | G | 71 | W | 87 | g | 103 | w | 119 | |||||
( | 40 | 8 | 56 | H | 72 | X | 88 | h | 104 | x | 120 | |||||
) | 41 | 9 | 57 | I | 73 | Y | 89 | i | 105 | y | 121 | |||||
* | 42 | : | 58 | J | 74 | Z | 90 | j | 106 | z | 122 | |||||
+ | 43 | ; | 59 | K | 75 | [ | 91 | k | 107 | { | 123 | |||||
, | 44 | < | 60 | L | 76 | \ | 92 | l | 108 | | | 124 | |||||
- | 45 | = | 61 | M | 77 | ] | 93 | m | 109 | } | 125 | |||||
. | 46 | > | 62 | N | 78 | ^ | 94 | n | 110 | ~ | 126 | |||||
/ | 47 | ? | 63 | O | 79 | _ | 95 | o | 111 |
変数は、宣言すれば使えます。 しかし、どこでも使えるわけではありません。 変数が使えるのは、ある一定の範囲内です。 変数の使える範囲を、変数の スコープ ( scope )と呼びます。
前回、メソッド定義の中で変数を宣言しました。 メソッド定義の中で宣言した変数は、そのメソッド定義の中でしか使えません。 呼び出し側は、 main というメソッドの定義と見なせます。 したがって、呼び出し側の中で宣言した変数も、呼び出し側の中でしか使えません。
次の例では、メソッド main で変数 x , メソッド test で変数 y を宣言しています。 メソッド main では、 main の x は使えますが、 test の y は使えません。 メソッド test では、 test の y は使えますが、 main の x は使えません。
/* 1*/ class VariableScope1 { // 変数のスコープ1 /* 2*/ public static void main (String[] args) { /* 3*/ int x = 100; // xを宣言 /* 4*/ test(); /* 5*/ System.out.println("main x = " + x); /* 6*/ // testのyは使えない /* 7*/ } /* 8*/ static void test () { /* 9*/ int y = 200; // yを宣言 /* 10*/ System.out.println("test y = " + y); /* 11*/ // mainのxは使えない /* 12*/ } /* 13*/ }
asiaa1:~/comp2b b08a001$ java VariableScope1 test y = 200 main x = 100 asiaa1:~/comp2b b08a001$
では、呼び出し側とメソッド定義の間でデータを交換するには、どうしたらよいでしょう。 正解は、引数と返り値を使う、です。 呼び出し側からメソッド定義にデータを伝えるには、引数を使います。 メソッド定義から呼び出し側にデータを伝えるには、返り値を使います。
次の例では、メソッド main の x の値をメソッド test に伝えるために、引数を使って、その値を x2 に格納しています。 また、メソッド test の y の値をメソッド main に伝えるために、返り値を使って、その値を y2 に格納しています。
/* 1*/ class VariableScope2 { // 変数のスコープ2 /* 2*/ public static void main (String[] args) { /* 3*/ int x = 100, y2; /* 4*/ y2 = test(x); // testのyをy2に格納 /* 5*/ System.out.println("test y = " + y2); /* 6*/ } /* 7*/ static int test (int x2) { // mainのxをx2に格納 /* 8*/ int y = 200; /* 9*/ System.out.println("main x = " + x2); /* 10*/ return y; /* 11*/ } /* 12*/ }
asiaa1:~/comp2b b08a001$ java VariableScope2 main x = 100 test y = 200 asiaa1:~/comp2b b08a001$
さて、呼び出し側とメソッド定義で同じ名前の変数を宣言しても、それらは別の変数と見なされます。
次の例では、メソッド main とメソッド test の両方で、変数 x を宣言しています。 メソッド main で x に100を格納し、メソッド test で x の値を200に変更しているように見えます。 しかし、 main の x の値は100のままです。 メソッド test では、 main の x でなく、 test の x に200を格納したのです。
/* 1*/ class VariableScope3 { // 変数のスコープ3 /* 2*/ public static void main (String[] args) { /* 3*/ int x = 100; /* 4*/ test(); // xは変わらない /* 5*/ System.out.println("main x = " + x); /* 6*/ } /* 7*/ static void test () { /* 8*/ int x = 200; // testのxに格納したから /* 9*/ System.out.println("test x = " + x); /* 10*/ } /* 11*/ }
asiaa1:~/comp2b b08a001$ java VariableScope3 test x = 200 main x = 100 asiaa1:~/comp2b b08a001$
どうしても、呼び出し側とメソッド定義で同じ変数を使いたい場合は、
クラス変数
(
class variable
)というものを使います。
これは、
class
の直下で宣言する変数で、
static int variable;
などと書きます。 クラス変数は、呼び出し側でもメソッド定義でも同じ変数と見なされます。
次の例では、クラス変数 x を宣言しています。 メソッド main で x に100を格納し、メソッド test で x の値を200に変更します。 今度は、 main でも test でも、 x の値は200になります。
/* 1*/ class VariableScope4 { // 変数のスコープ4 /* 2*/ static int x; // mainでもtestでも使える /* 3*/ public static void main (String[] args) { /* 4*/ x = 100; /* 5*/ test(); // xは変わる /* 6*/ System.out.println("main x = " + x); /* 7*/ } /* 8*/ static void test () { /* 9*/ x = 200; // クラス変数xに格納したから /* 10*/ System.out.println("test x = " + x); /* 11*/ } /* 12*/ }
asiaa1:~/comp2b b08a001$ java VariableScope4 test x = 200 main x = 200 asiaa1:~/comp2b b08a001$
今まで定義したメソッドは、引数が整数や実数のものばかりでした。 メソッドは整数や実数に限りません。 引数が配列であるメソッドも定義できます。 これによって、配列に関する処理にも名前を付けることができます。
引数が配列であるメソッドを定義するには、整数のときの
int
の代わりに、
int
[]と書きます。
値を返さないメソッドならば、
static void methodname (int[] argument, ...) { statement; ... }
と書き、整数(
int
型)を返すメソッドならば、
static int methodname (int[] argument, ...) { statement; ... }
と書きます。
メソッドを呼び出すには、引数に配列の変数名のみ書きます。 引数に[]は書きません。 値を返さないメソッドを呼び出すには、文として
methodname(argument, ...);
と書きます。 値を返すメソッドを呼び出すには、式として
methodname(argument, ...)
と書きます。
例として、配列要素を全て出力するプログラム
/* 1*/ class ArrayPrint2 { // 配列の出力2 /* 2*/ public static void main (String[] args) { /* 3*/ int[] array = {100, 110, 120, 130, 140}; /* 4*/ int i; /* 5*/ for (i = 0; i < array.length; i++) { /* 6*/ System.out.print(array[i] + " "); /* 7*/ } /* 8*/ System.out.println(); /* 9*/ } /* 10*/ }
asiaa1:~/comp2b b08a001$ java ArrayPrint2 100 110 120 130 140 asiaa1:~/comp2b b08a001$
を、メソッドを使って書き直します。
メソッドの名前は
printBySpace
とします。
このメソッドの引数は、配列
a
です。
このメソッドは値を返さないので、
static void
と指定します。
/* 1*/ class ArrayPrint3 { // 配列の出力3 /* 2*/ public static void main (String[] args) { /* 3*/ int[] array = {100, 110, 120, 130, 140}; /* 4*/ printBySpace(array); // 実引数は配列の変数名 /* 5*/ System.out.println(); /* 6*/ } /* 7*/ static void printBySpace (int[] a) { // 仮引数も配列の変数名 /* 8*/ int i; /* 9*/ for (i = 0; i < a.length; i++) { /* 10*/ System.out.print(a[i] + " "); /* 11*/ } /* 12*/ } /* 13*/ }
次の例は、配列要素の合計を計算するプログラム
/* 1*/ class ArraySum2 { // 配列の合計2 /* 2*/ public static void main (String[] args) { /* 3*/ int[] array = {100, 110, 120, 130, 140}; /* 4*/ int i, sum = 0; /* 5*/ for (i = 0; i < array.length; i++) { /* 6*/ sum += array[i]; /* 7*/ } /* 8*/ System.out.println(sum); /* 9*/ } /* 10*/ }
asiaa1:~/comp2b b08a001$ java ArraySum2 600 asiaa1:~/comp2b b08a001$
を、メソッドを使って書き直します。
メソッドの名前は
getSum
とします。
このメソッドの引数は、配列
a
です。
このメソッドは整数(
int
型)を返すので、
static int
と指定します。
/* 1*/ class ArraySum3 { // 配列の合計3 /* 2*/ public static void main (String[] args) { /* 3*/ int[] array = {100, 110, 120, 130, 140}; /* 4*/ System.out.println(getSum(array)); /* 5*/ } /* 6*/ static int getSum (int[] a) { /* 7*/ int i, sum = 0; /* 8*/ for (i = 0; i < a.length; i++) { /* 9*/ sum += a[i]; /* 10*/ } /* 11*/ return sum; /* 12*/ } /* 13*/ }
メソッドは、似た処理があるときに便利になります。 ここで、次の出力が得られるようなプログラムを考えます。
asiaa1:~/comp2b b08a001$ java ArrayPrintSum 100 110 120 の合計は330 100 110 120 130 の合計は460 100 110 120 130 140 の合計は600 asiaa1:~/comp2b b08a001$
データは次のように配列で与えます。
int[] array1 = {100, 110, 120}; int[] array2 = {100, 110, 120, 130}; int[] array3 = {100, 110, 120, 130, 140};
上記の2つのメソッドを利用すれば、短いプログラムで書けるのです。
/* 1*/ class ArrayPrintSum { // 配列の出力と合計 /* 2*/ public static void main (String[] args) { /* 3*/ int[] array1 = {100, 110, 120}; /* 4*/ int[] array2 = {100, 110, 120, 130}; /* 5*/ int[] array3 = {100, 110, 120, 130, 140}; /* 6*/ printBySpace(array1); /* 7*/ System.out.println("の合計は" + getSum(array1)); /* 8*/ printBySpace(array2); /* 9*/ System.out.println("の合計は" + getSum(array2)); /* 10*/ printBySpace(array3); /* 11*/ System.out.println("の合計は" + getSum(array3)); /* 12*/ } /* 13*/ static void printBySpace (int[] a) { /* 14*/ int i; /* 15*/ for (i = 0; i < a.length; i++) { /* 16*/ System.out.print(a[i] + " "); /* 17*/ } /* 18*/ } /* 19*/ static int getSum (int[] a) { /* 20*/ int i, sum = 0; /* 21*/ for (i = 0; i < a.length; i++) { /* 22*/ sum += a[i]; /* 23*/ } /* 24*/ return sum; /* 25*/ } /* 26*/ }
次の出力が得られるようなプログラムを考えます。
asiaa1:~/comp2b b08a001$ java ArrayPrintAverage 100,110,120,の平均は110 100,110,120,130,の平均は115 100,110,120,130,140,の平均は120 asiaa1:~/comp2b b08a001$
データは次のように配列で与えます。
int[] array1 = {100, 110, 120}; int[] array2 = {100, 110, 120, 130}; int[] array3 = {100, 110, 120, 130, 140};
配列要素をコンマ区切りですべて出力するメソッド printByComma と、配列要素の平均を計算するメソッド getAverage を自分で定義し、それらのメソッドを呼び出して、上記の出力が得られるプログラムを作成してください。
平均が計算できるようにするために、配列の要素数は1以上であると仮定してください。 また、平均の計算を実数にする必要はありません。
余力のある人は、メソッド printByComma を改良して、余計なコンマが出力されないようにしてください。
asiaa1:~/comp2b b08a001$ java ArrayPrintAverage2 100,110,120の平均は110 100,110,120,130の平均は115 100,110,120,130,140の平均は120 asiaa1:~/comp2b b08a001$
今日の演習12の答案(Javaプログラム)をメールで提出してください。 差出人は学内のメール・アドレス(b08a001@cis.twcu.ac.jpなど)とし、宛先はkonishi@cis.twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(7月9日)を明記してください。