[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

コンピュータIIB(Javaプログラミング入門)第10回

目次 索引
10.1 データ型
10.1.1 データ型とは
10.1.2 整数と浮動小数点数
10.1.3 真理値とブール式
10.1.4 文字
10.2 他のクラスのメソッド
10.3 インスタンスメソッド
10.3.1 インスタンスメソッドとは
10.3.2 メッセージ受渡しモデル
10.3.3 インスタンスメソッドの使用例
10.4 演習10
10.5 レポート課題
10.6 参考文献
ASCII  Unicode  基本データ型  参照データ型  真理値  データ型  バイト  ビット  ブール式  浮動小数点数  メッセージ受渡しモデル  文字符号  論理型 

10.1 データ型

10.1.1 データ型とは

データ型data type ) とは、データの種類のことです。 これまでに、整数、配列、およびクラスの3種類のデータ型を扱ってきました。 Java言語には、この他のデータ型も用意されています。

Java言語のデータ型は、まず基本データ型と参照データ型の2つに大きく分類されます。 基本データ型primitive data type ) には、整数型、浮動小数点数型、論理型、および文字型があります。 参照データ型reference data type ) には、クラス型と配列型があります。 以下は基本データ型の詳細です。

表 10.1  Java言語の基本データ型
種類 型名 ビット 説明
整数型 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ビット単位であるのは、ここに理由があります。

10.1.2 整数と浮動小数点数

整数を扱う場合、普通は int 型を用います。 ただし、 int 型は9桁程度が限界であり、これを超えますと意味のない計算をしてしまいます。 int 型の範囲を超えるような大きい数を扱うときに、 long 型を用います。

浮動小数点数floating point number ) とは、小数点をずらすことによって、非常に大きな数や非常に小さな数も表現できるようにした小数のことです。 浮動小数点数を扱う場合、普通は double 型を用います。 限られたビット数で表現する以上、小数点をずらす桁数には限度がありますし、小数の精度にも限界があります。

10.1.3 真理値とブール式

論理型logical type ) とは、真理値を表わすデータ型です。 ここで 真理値truth value ) とは、真を表す記号 true と偽を表す記号 false のことだと思ってください。 Java では、型名 boolean で論理型を表わします。 値が論理型である式を、 ブール式Boolean expression ) とよびます。 これまで「条件が成り立つ」、「条件が成り立たない」と言ってきたことは、正確にはブール式の値が true になること、false になることです。

10.1.4 文字

Javaは、文字( char 型)を1バイトではなく2バイトで表現します。 これは、英数字だけではなく、漢字なども文字として扱おうという設計です。 なお、ちょうど1バイトで表現されるデータ型として、バイト( byte )が用意されています。

文字は、内部では整数として処理されます。 この、文字から整数への対応を 文字符号character code ) と呼びます。 Javaの採用している文字符号は、 Unicode と呼ばれる体系です。 Unicodeは ASCII という体系の拡張になっています。 主な文字のASCII符号は次の通りです。

表 10.2  主な文字の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

プログラムの中で文字を表す場合、その文字をシングルクオート( ' )で囲みます。 ただし、シングルクオート自身、およびダブルクオート( " )、バックスラッシュ( \ )については、それぞれ '\'' , '\"' , '\\' とします。


10.2 他のクラスのメソッド

前回、以下のようなプログラムを紹介しました。

Time.java
/*  1*/ class Time {
/*  2*/     int hour, minute;
/*  3*/ }
TimeTest5.java
/*  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*/ }
b04a001@AsiaA1:~/comp2b% java TimeTest5
14:45
14:30
b04a001@AsiaA1:~/comp2b%

ファイルTime.javaではクラスの定義を行い、ファイルTimeTest5.javaでは実行プログラムとメソッドの定義を行っています。 次のようにしますと、クラス定義とメソッド定義を一つにまとめることができます。

Time.java(第2版)
/*  1*/ class Time {
/*  2*/     int hour, minute;
/*  3*/     static int getHour (Time t) {
/*  4*/         return t.hour;
/*  5*/     }
/*  6*/     static int getMinute (Time t) {
/*  7*/         return t.minute;
/*  8*/     }
/*  9*/     static void setHour (Time t, int hour) {
/* 10*/         t.hour = hour;
/* 11*/     }
/* 12*/     static void setMinute (Time t, int minute) {
/* 13*/         t.minute = minute;
/* 14*/     }
/* 15*/ }
TimeTest5.java(第2版)
/*  1*/ class TimeTest5 {
/*  2*/     public static void main (String[] args) {
/*  3*/         Time x = new Time();
/*  4*/         Time.setHour(x, 14);
/*  5*/         Time.setMinute(x, 45);
/*  6*/         System.out.println(Time.getHour(x) + ":" + Time.getMinute(x));
/*  7*/         Time.setMinute(x, 30);
/*  8*/         System.out.println(Time.getHour(x) + ":" + Time.getMinute(x));
/*  9*/     }
/* 10*/ }

メソッド定義の形は同じですが、メソッド呼出しの形は変わります。 値を返さないメソッドを呼び出すには、文

classname.methodname(argument, ...);

を用います。 ここで classname は、メソッドが定義されているクラスの名前です。 値を返すメソッドを呼び出すには、式

classname.methodname(argument, ...)

を用います。


10.3 インスタンスメソッド

10.3.1 インスタンスメソッドとは

以前、メソッドにはインスタンスメソッドとクラスメソッドがあると言いました。 これまではクラスメソッドのみを使ってきましたが、Javaらしいプログラムではインスタンスメソッドのほうがよく用いられます。 クラスメソッドと比較しながら、インスタンスメソッドについて説明します。

上記のプログラムを、インスタンスメソッドを用いて書きなおしますと、次のようになります。

Time.java(第3版)
/*  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*/ }
TimeTest5.java(第3版)
/*  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*/ }

まず、メソッド定義を実行プログラム( main )には並べて書かず、フィールド定義に並べて書きます。 レコード型としてのクラスはフィールドとコンストラクタを定義しますが、一般のクラスはさらにメソッドも定義します。 メソッドは、実行プログラムよりもデータ(インスタンス)に強く結び付くと考えます。

次に、キーワード static を取り除きます。 メソッド定義で static と書くとクラスメソッド、書かないとインスタンスメソッドになります。

メソッド呼出しの形も変えます。 値を返さないインスタンスメソッドを呼び出すには、文

instance.methodname(argument, ...);

を用います。 ここで instance は、インスタンスを値とする式です。 例えば、インスタンス(への参照)が格納された変数などです。 値を返すインスタンスメソッドを呼び出すには、式

instance.methodname(argument, ...)

を用います。 なお、括弧がなければインスタンスのフィールドにアクセスする形になります。

この式 instance は、メソッド呼出しの実引数としての役割を果たします。 この実引数に対応する仮引数は、メソッド定義でのキーワード this です。 メソッド呼出しの際、 this にはインスタンス instance への参照がコピーされます。

10.3.2 メッセージ受渡しモデル

インスタンスメソッドとは、引数の中からインスタンスを一つ選び、それを特別扱いしたものと考えてください。 特別扱いされたインスタンスは、実引数としては、括弧の中ではなく、メソッド名の左に書かれます。 仮引数としては、括弧の中では定義されず、キーワード this で表されます。

この、引数の一つのインスタンスを特別扱いすることは、 メッセージ受渡しモデルmessage-passing model ) に基づいています。 これは、データ(インスタンス)がメッセージを受け取ると、それに応じて操作(メソッド)が引き起こされるという考え方です。 Javaでのメッセージは、メソッド名のことだと思ってください。 インスタンスにメッセージを送りますと、そのインスタンスのクラスで定義されたメソッドが起動されるということです。 メッセージ受渡しモデルに従いますと、上記のメソッド呼出しは、インスタンス instance にメッセージ methodname ( argument , ... ) を送ることに相当します。

インスタンスメソッドにできて、クラスメソッドにできないことのひとつに、メソッド定義で this を用いることがあげられます。 this は、インスタンスメソッドの呼出しのときにメッセージを受け取ったインスタンスを指します。 クラスメソッドでは、メッセージを受け取るインスタンスが存在しませんので、 this が使えないのです。

10.3.3 インスタンスメソッドの使用例

前回は、以下のようなプログラムで、生まれた年の計算をしました。

Person.java
/*  1*/ class Person {
/*  2*/     int age, year;
/*  3*/     Person (int age, int year) {
/*  4*/         this.age = age;
/*  5*/         this.year = year;
/*  6*/     }
/*  7*/ }
PersonMain.java
/*  1*/ class PersonMain {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         Person[] persons = {
/*  5*/             new Person(20, 2005),
/*  6*/             new Person(15, 2005),
/*  7*/             new Person(10, 2005),
/*  8*/             new Person(5, 2005),
/*  9*/             new Person(0, 2005)
/* 10*/         };
/* 11*/         for (i = 0; i < persons.length; i++) {
/* 12*/             System.out.print(persons[i].age);
/* 13*/             System.out.print(" years old in ");
/* 14*/             System.out.print(persons[i].year);
/* 15*/             System.out.print(", ");
/* 16*/             persons[i].year = persons[i].year - persons[i].age;
/* 17*/             persons[i].age = 0;
/* 18*/             System.out.print(persons[i].age);
/* 19*/             System.out.print(" years old in ");
/* 20*/             System.out.print(persons[i].year);
/* 21*/             System.out.println();
/* 22*/         }
/* 23*/     }
/* 24*/ }
b04a001@AsiaA1:~/comp2b% java PersonMain
20 years old in 2005, 0 years old in 1985
15 years old in 2005, 0 years old in 1990
10 years old in 2005, 0 years old in 1995
5 years old in 2005, 0 years old in 2000
0 years old in 2005, 0 years old in 2005
b04a001@AsiaA1:~/comp2b%

これを、インスタンスメソッドを用いて書き直しますと、次のようになります。

ファイルPerson.javaでは、メソッド toBirthYear を定義します。 このメソッドは、0才のときのデータに変更するものです。 このメソッドに引数はありません。 このメソッドは値を返しませんので、 void と指定します。

また、メソッド printPerson も定義します。 このメソッドは、西暦何年に何才かを出力するものです。 このメソッドに引数はありません。 このメソッドは値を返しませんので、 void と指定します。

Person.java(第2版)
/*  1*/ class Person {
/*  2*/     int age, year;
/*  3*/     Person (int age, int year) {
/*  4*/         this.age = age;
/*  5*/         this.year = year;
/*  6*/     }
/*  7*/     void toBirthYear () {
/*  8*/         this.year = this.year - this.age;
/*  9*/         this.age = 0;
/* 10*/     }
/* 11*/     void printPerson () {
/* 12*/         System.out.print(this.age);
/* 13*/         System.out.print(" years old in ");
/* 14*/         System.out.print(this.year);
/* 15*/     }
/* 16*/ }

ファイルPersonMain.javaでは、インスタンスメソッド toBirthYearprintPerson を呼び出します。 14行目は、 i 番目の人を表すインスタンス persons [ i ] に、0才のときのデータに変更するようにとメッセージ toBirthYear () を送るという意味です。 また、12行目と15行目は、インスタンス persons [ i ] に、西暦何年に何才かを出力するようにとメッセージ printPerson () を送るという意味です。

PersonMain.java(第2版)
/*  1*/ class PersonMain {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         Person[] persons = {
/*  5*/             new Person(20, 2005),
/*  6*/             new Person(15, 2005),
/*  7*/             new Person(10, 2005),
/*  8*/             new Person(5, 2005),
/*  9*/             new Person(0, 2005)
/* 10*/         };
/* 11*/         for (i = 0; i < persons.length; i++) {
/* 12*/             persons[i].printPerson();
/* 13*/             System.out.print(", ");
/* 14*/             persons[i].toBirthYear();
/* 15*/             persons[i].printPerson();
/* 16*/             System.out.println();
/* 17*/         }
/* 18*/     }
/* 19*/ }

10.4 演習10

ある鉄道会社で、旅行のキャンペーンを行っているとします。 そのキャンペーンとは、乗車券と特急券の合計が5千円以上ならば、乗車券を1割引するというものです。 これまでに、次の5人の旅行客が乗車券と特急券を購入したとします。 割引前の乗車券と特急券を格納した後、それらを割り引くという計算をしてください。

表 10.3  乗車券と特急券の割引
割引前 割引後
乗車券 特急券 合計 乗車券 特急券 合計
2000 1000 3000 2000 1000 3000
3000 1000 4000 3000 1000 4000
3000 2000 5000 2700 2000 4700
4000 2000 6000 3600 2000 5600
4000 3000 7000 3600 3000 6600

ファイルTrip.javaでは、乗車券と特急券を格納するために、クラス Trip を定義します。 フィールド ticket には乗車券を、 express には特急券を格納します。 コンストラクタは、引数が ticket , express の順になるように定義します。

ファイルTrip.javaでは、インスタンスメソッド discount を定義します。 これは、乗車券と特急券の合計が5千円以上ならば、乗車券を1割引するものです。 このメソッドに引数はありません。 このメソッドは値を返しませんので、 void と指定します。 メソッド定義の要点は、1割引の計算は、9倍して10で割ることです。

ファイルTrip.javaでは、インスタンスメソッド printTrip を定義します。 これは、「乗車券+特急券=合計」を出力するものです。 このメソッドに引数はありません。 このメソッドは値を返しませんので、 void と指定します。 メソッド定義の要点は、合計の部分は式の値を出力することです。

ファイルTripMain.javaでは、次のようにコンストラクタを呼び出して、配列 trips にすべての旅行客の乗車券と特急券を格納します。

Trip[] trips = {
    new Trip(2000, 1000),
    new Trip(3000, 1000),
    new Trip(3000, 2000),
    new Trip(4000, 2000),
    new Trip(4000, 3000)
};

一人一人の旅行客に対して、メッセージ printTrip () を送って割引前を画面に出力し、メッセージ discount () を送って割引をし、メッセージ printTrip () を送って割引後を画面に出力するというアルゴリズムに従って、プログラムを作成してください。

b04a001@AsiaA1:~/comp2b% java TripMain
2000+1000=3000 -> 2000+1000=3000
3000+1000=4000 -> 3000+1000=4000
3000+2000=5000 -> 2700+2000=4700
4000+2000=6000 -> 3600+2000=5600
4000+3000=7000 -> 3600+3000=6600
b04a001@AsiaA1:~/comp2b%

余力のある人は、これとは別に、クラスメソッドを用いたプログラムを作成してください。 ファイルTrip2.javaでは、フィールド、コンストラクタ、クラスメソッドを定義し、ファイルTripMain2.javaでそれらを呼び出すものとします。


10.5 レポート課題

今日の演習10の答案(Javaプログラム)をメールで提出してください。 メールの送信には学内のコンピュータ(メール・サーバ)を用い、送信先はkonishi@twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(6月24日)を明記してください。


10.6 参考文献


[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

2005年6月24日更新
小西 善二郎 <konishi@twcu.ac.jp>
Copyright (C) 2005 Zenjiro Konishi. All rights reserved.