データ型

コンピュータ用語の中には日常聞きなれない単語があります。「リテラル」もそのような用語の一つです。リテラルとはプログラムの中で具体的な値を直接書いた時の、その値を指します。

int num = 10;
char moji = ‘A’;
return true;

英語の意味は「(意味が)文字通りの」、「事実に即した」、「融通が利かない」などで、「そのものズバリで、変化しない」といったイメージでしょう。
プログラムの中でのリテラルには数値リテラル、文字リテラル、文字列リテラルがあります。

各種リテラル

種類 表記
整数 10進数 先頭が(マイナス符号を含む)1~9で始まる0~9の整数、但し一桁の場合は0も可 -8
16
2進数 先頭が0b(又は0B)で始まる0及び1を使ったビット列 -0b1000
0b10000
8進数 先頭が0(8進数を表す文字記号)で始まる0~7の数列 -010
020
16進数 先頭が0x(又は0Xの16進数を表す文字記号)で始まる0~9及びa~f(又はA~F)の16進数列 -0x10
0x20
浮動小数点数 標準表記 10進数の実数(整数部、小数点、小数部) -8.0
16.0
指数表記 Eを底とする指数表記(仮数部、e(又はE)、指数部) -8.0e+0
1.6e+1
文字 シングルクォーテーションで1文字を囲う。文字はユニコードで規定される範囲。 ‘a’
‘A’
文字列 ダブルクォーテーションで文字列を囲う。文字列内の文字はユニコードで規定される範囲。 “A”
“ABC”

リテラルに対して、変化する値を扱うのが変数です。
メモリー上の特定の領域に名前を付けて、その名前でその領域にデータを記録したり、書き換えたり、参照できる。これが変数であり革新的なアイディアでした。プログラム言語はここから始まったといっても良いでしょう。
しかし、変数だけでは解決しない事がありました。それは変数の型です。
リテラルはその物のズバリの表現なので、コンパイラーはその表現に合わせ必要な記憶領域を決まることが出来ましたが、変数は単なる名前であり、メモリー上の番地を示しているだけです。コンパイラはどのくらいの記憶領域をそれぞれの変数に対して割り当ててよいのか分かりません。そこで、変数ごとに記憶するデータに合わせた型を宣言してもらう必要がありました。

変数の宣言

書式

データ型  変数名;

同一型の変数は「,」で区切り一行に複数書くことが出来ます。
但し、変数ごとのコメントは付けられないので要注意

データ型  変数1の名前, 変数2の名前, … ;
変数の宣言はC言語などオブジェクト指向プログラミング以前のプログラム言語では、プログラムの先頭で宣言するのが決まりですが、Javaではプログラムの可読性を上げるため、変数宣言は変数を使用する直前に行う事が推奨されています。

データ型
データ型はプログラム言語により(開発思想の違いから)若干の違いがあります。
Javaでは大きく基本(プリミティブ)型、参照型の二つに分かれます。

基本型は4種類、8型に分かれています。

種類 型名 ビット幅 備考
整数 byte 8
short 16
int 32 リテラルのデフォルト
long 64
浮動小数点数 float 32
doubl 64 リテラルのデフォルト
文字 char 16 ユニコード1文字のみ
真偽値 boolean true/false(小文字のみ)

※型名は小文字のみ

(C言語と比べた)Javaの型の特徴

数値と文字は型として独立している。
文字数(記憶領域サイズ)の確定している文字は基本型、文字数の確定しない文字列は参照型。文字列の内容が1文字でも文字列は文字列で、扱いは異なる。
真偽値が基本型として存在し、数値(0や1)での真偽値表現はしない。

データ型ごとのデフォルト値

データ型 デフォルト値
整数 0
実数 0.0
文字 ‘¥u0000’
(印字は半角の空白)
真偽値 false
基本型の変数は宣言によりメモリ上に記憶領域が確保され、デフォルト値で初期化されます。
但し、デフォルト値のままではコンパイルエラーになり、明示的な代入又は初期化演算子による初期値設定が必須です。

参照型は配列や文字列、オブジェクトなど構造を持ったデータの型で、記憶領域のサイズが個々に異なるためデータの実体と実体への参照情報をセットにしてデータを記憶します。また、サイズの決まった情報とサイズが任意の情報を効率よく管理するため、この二つの情報はJVMが管理するメモリ空間の中の別々の領域に記憶されています。
Javaは基本的にプログラマにメモリ管理を意識させない言語ですが、この参照型は記憶領域の確保法が基本型と異なるので、JVMのメモリ管理について少し詳しく見てみましょう。

参照型データの記憶
JVMの管理するメモリ空間には、管理方式の異なる領域がいくつかありますが、参照型データはスタックとヒープという領域を使って記憶します。

スタック(Stack)
線形のデータ構造で、プッシュ/ポップによる簡潔な管理の為素早いアクセスができます。メソッドの実行順の制御情報、ローカル変数の基本型の値や参照型の実体参照情報を記憶します。
メソッドの再帰呼び出しなどでこの領域が一杯になると、JVMはStackOverflowErrorが発生します。

ヒープ(Heap)
アクセスは低速ですがガーベージコレクションを含めた複雑な管理が行われる非常に大きな領域です。クラスのインスタンス、参照型データの実体など動的なデータを記憶する領域でガーベージコレクションの対象になっています。なお、クラス構造やコンスタントプールなど静的なデータはピープの一部であるメソッド・エリアに記憶されます。
インスタンスや参照型データを大量に作成しヒープが一杯になると、JVMはOutOfMemoryErrorを発生します。

参照型データのメモリー上の配置

参照型データの実体はヒープ領域に確保され、ここへの参照情報がスタック領域に確保されます。

配列データの記憶
参照型データの一つである配列を使って、参照型データの情報がどのように管理されているか次のケースで見てみましょう。

1)
int型で要素が1つの配列を二つ(intArry1とintArry2)を作ります。
2)
intArry1の配列変数(配列の実体を参照する情報)をintArry2の配列変数に代入します。
3)
intArry1の実体の内容を変更し、intArry2の内容はどうなるか確認します。
プログラム

class TestArray {
	public static void main(String[] args) {
		int[] intArry1 = new int[1];
		int[] intArry2 = new int[1];
		System.out.print("intArry1[0]=" + intArry1[0] + "\nintArry2[0]=" + intArry2[0] + "\t\t... 1");			// 1)

		intArry1[0] = 1;
		intArry2 = intArry1;
		System.out.print("\nintArry1[0]=" + intArry1[0] + "\nintArry2[0]=" + intArry2[0] + "\t\t... 2");		// 2)

		intArry1[0] = 10;
		System.out.print("\nintArry1[0]=" + intArry1[0] + "\nintArry2[0]=" + intArry2[0] + "\t\t... 3");		// 3)
	}
}

実行結果

>java TestArray
intArry1[0]=0
intArry2[0]=0 … 1
intArry1[0]=1
intArry2[0]=1 … 2
intArry1[0]=10
intArry2[0]=10 … 3
>

配列の参照経路と配列要素の内容変化
上記の各ケースにおいて参照型データの情報がスタックとヒープ間でどのように管理されているのか見てみましょう。

1)
intArry1、intArry2の実体用の領域がヒープに、そこへの参照情報がスタックに格納され、各配列の実体(唯一の要素である0番目の要素)にはint型のデフォルト初期値0が入ります。
2)
intArry2の配列参照情報にintArry1の配列参照情報を代入したため、intArry1もintArry2も同じ配列を参照します。このため、intArry2の要素には値を代入していないのに、整数リテラル1を代入したintArry1の要素と同じ値になっています。
3)
また、intArry1の要素の内容を変更すると、intArry2の要素の内容も同じ値に変ります。

以上のように、配列など参照型データは実体とその参照情報の組み合わせで管理されるため、その扱いには注意が要ります。
なお、参照型でもString型はプログラムの中で頻繁に使われる文字列としての扱いが更に加わるので、他の参照型データとは異なる独自の挙動を持っています。

プログラミングに戻る

時代背景

コンピュータの誕生については諸説あります
というのは機械式および電気式の計算機械は19世紀からありましたし、1940年代には暗号解読や弾道計算専用の電子機械式の計算機がいくつか作られていました。
フォン・ノイマンが提唱したプログラム内蔵方式(当初のENIACには実装されていない)と逐次処理方式をコンピュータの要件とするなら、やはり1946年に米国で開発されたENIACが最初の汎用コンピュータでしょう。ENIACは当初陸軍の資金で弾道計算用に開発されましたが、水爆開発でも使われたといわれています。

ENIACは当時の電気機械式計算機に比べ約1000倍の計算能力があったといわれていますが、プログラミングは大変だったようです。
ENIACはループや分岐、サブルーチンなどが可能で紙上でプログラムが完成しても、プログラムをENIACに設定するため、搭載されている乗算器や除算器の組み合わせをスイッチやケーブルの配線を数日かけて変更しなければいけませんでした。
数学の専門家が何日もかかったプログラミングも、1948年プログラム内蔵方式が実装された改良版ENIACによって数時間に短縮されます。しかし、ENIACの設計は特殊でその後他のコンピュータでは採用されませんでした。

1950年代に入ると軍用目的でない、商用コンピューターがUNIVAC(51年)、IBM(52年)から発表されます。
当時、プログラム言語はCPUが直接実行できる二進数を並べた機械語か、機械語をニーモニックと呼ぶ英単語の省略文字で表し命令語とするアセンブラ言語しかありませんでした。しかし、商用コンピュータの拡販のためにもより一般的な数式表現や英語表現で開発できるプログラム言語の必要性が高まり、

1954年
Fortran
科学技術計算向けプログラム言語
1959年
COBOL
事務処理向けプログラム言語

が発表され、人間が理解しやすい表現でプログラムが記述できるようになり、プログラム開発を専門に行う技術者によりプログラムが量産されるようになり、銀行や商社、大手製造企業への本格的な普及が始まりました。
また、1950年代半ばにはコンピュータの素子が真空管からトランジスタに変わり、トランジスタの小型、省電力、小発熱性からコンピュータ自体の小型化・低価格化が進みます。

1960年代に入るとハードウェアの技術革新は周辺装置にもおよび、磁気ディスク装置や高速データー転送バスなどによりコンピュータの利用分野はますます広がり、1964年にはDECが16,000ドルでミニコンピュータを販売、それまで利用が大企業に限られていたコンピュータの一般企業への普及が始まります。それに合わせてソフトウェアに対する需要は増大、1960年代後半には深刻なソフトウェアエンジニア不足が予測され「ソフトウェア危機」が叫ばれました

この状況の中

ソフトウェアの生産性を向上するためソフトウェア開発プロセスを工学的に改革する研究
移植性の高いプログラム言語の開発研究

が始まりました。

プログラムはどうあるべきかという研究の結果、1969年エドガー・ダイクストラが「構造化プログラミング」を提唱。正しいプログラムを作るためには、プログラムは上手く構造化されなければならないとして、構造化の条件を提示しました。
移植性の高いプログラム言語に対する需要は、ハードウェア技術の革新により多くのメーカーがコンピュータを提供するようになったため、研究所などでは異なるOS、異なるCPUアーキテクチャー間でのソフトウェアの共用のため、ソースプログラム互換のコンパイラーを前提としたC言語が、1972年At&Tベル研究所で開発されました。

1970年代にはマイクロコンピュータ、1980年代にはパーソナルコンピュータといわゆるダウンサイジングが加速します。プログラム言語の世界でも、ソフトウェアの大量生産、大規模開発に対応するためさらなる生産性の向上が望まれ、構造化プログラミングでは整理されなかった「データ」の扱いについても研究が行われました。
そして、データの型に基づいたいくつもの実体(インスタンス)を上手く管理する仕組みとしてクラスとその継承といった考慮からオブジェクト指向概念が生まれ、その概念を実装したプログラム言語が次々に発表されました。

Javaもこれらオブジェクト指向プログラミング言語のひとつとしてサン・マイクロシステムズにより開発されましたが、その開発経緯は他のプログラム言語とは多少異なっています。そもそも、サン・マイクロシステムズは2010年にオラクルにより吸収合併されるまでPCの上位に位置づけられていたワークステーションメーカーでした。サンの名前自体Stanford University Networkの頭文字であり、スタンフォード大学の校内ネットワーク用のワークステーション開発から1982年に創業し、1985年にはRISCチップまで自社開発していました。

そのサンが1990年代に入ると今後の有力市場は家電製品だと考え、その処理系を開発できるプログラム言語の開発に着手し、1995年にJavaの名前で発表しました。
家電製品向けの新しいプログラム言語を考えると、情報処理の専門家だけでなく一般技術者でも安全で保守性の高いプログラムが開発出来なければいけません。そこで

プラットフォーム非依存で、ハードウェアの変更に即対応できる高い移植性
コンパイラ及び実行環境による安定的プログラム稼働の検証(厳密な言語仕様とコンパイラ、JVMによる実行前検証)
プログラム実行中に生じた異常の適切な処理機構の装備(例外処理)
プログラマのメモリ管理負担の軽減(ガーベージコレクタの採用)
メモリ破壊を起こさない言語仕様(ポインターによるメモリアクセスの禁止)

など、生産性向上のためのオブジェクト指向プログラミングだけでない工夫がJavaには盛り込まれました

当初の家電製品市場への進出は時期尚早だったのか成功しませんでしたが、紆余曲折の末1990年台後半に始まるインターネットの急成長に乗り、サーバーサイドのアプリケーション開発で利用さえるようになり、近年では組み込みシステムや携帯機器、企業の基幹情報システムを担う大規模なデータベース、サーバ、スーパーコンピュータアプリケーションまで、多くの分野で使用されています。

Java言語に戻る

Java言語の特徴

Java言語はプログラミング言語の変遷の中では比較的新しい言語に属します。このため、それ以前開発されたプログラミング言語の利点や課題を踏まえています。
主にSmalltalkとC言語(C++を含む)をルーツとし、多少の違いはあるものの構文はANSI-C、オブジェクト指向プログラミングはCから発展したC++及びSmalltalkの影響が大きいでしょう。

Java言語の特徴

– オブジェクト指向
オブジェクト指向の特徴はいくつかあります。オブジェクト指向を取り入れたプログラミング言語もいくつかあります。つまり、オブジェクト指向プログラミング言語といってもみな同じではありません。オブジェクト指向のとらえ方で言語が持つ特徴は変わります。
そのような中で、Javaは理想を追求したSmalltalkと実用性を重視したC++の影響を受け、両者の特徴をバランス統合してオブジェクト指向開発に必要な要素をすべてそろえている言語だといえるでしょう。
– 可搬性
プログラムはプラットフォームに依存しないバイトコードとしてコンパイルされ、JVM(Java仮想マシン)により実行されます。従って、Javaプログラムはコンパイルされた後でさえ、JVMを搭載したプラットフォームであれば、再コンパイルすることなく実行できます。この移植不要という特徴(可搬性)はプラットフォームを特定できないWeb環境で他言語にない特徴になっています。
– 例外処理
プログラムが実現する処理と処理の過程で発生する可能性のある外乱に対する処理を構造化して分離し、プログラムの可読性と頑健性を高める仕組み。
– ダイナミックリンク
実行に必要なバイトコードを実行時に探しだし動的に結合しプログラムを実行します。これによりプログラマは、プログラムの一部を改変したときでもプログラム全体を再コンパイルする必要がありません。
– 型チェック
静的な型を持つため、コンパイル時に可能な限りのエラーチェックを行います。更に、コンパイル時に最適化も行います。
– メモリ管理
メモリ管理をユーザに任せずJVMがガベージコレクションを行うので、実行中に使用されなくなったメモリは自動的に解放されるため、メモリリークなどのバグが発生しません。また、ポインタ操作が公開されていないためメモリ破壊などのバグ発生が軽減されています。
– マルチスレッド
マルチスレッド対応の言語であり、複数の処理を同時に行なう必要があるネットワークアプリケーションやGUIアプリケーションの記述に向いています。

なお、Java言語の大きな特徴であるオブジェクト指向はコンピュータの大幅な性能向上、コンピュータの利用分野の拡大に合わせ1960年台後半に危惧された「ソフトウェア危機」に対応するための研究から生まれた、大きなプログラムをブラックボック化した小さな複数のプログラム(オブジェクト)によって構成するプログラミング概念であり、仕組みです。

オブジェクト指向プログラミングの特徴

– カプセル化
データと振舞いを隠蔽する仕組み。
– 継承
既存クラスの機能、構造を共有する新たなクラスを生成することができ仕組み。
– ポリモーフィズム
プログラミング言語の各要素(定数、変数、オブジェクトなど)を異なる型に置き換えて扱う事を許す概念。

Java言語に戻る