page1(update:2017/10/02)


[ prev | next | index ]

1.Java言語の特徴 

言語IIではオブジェクト指向プログラミングを具体的に学ぶため、言語としてjavaを選びました。
 他のオブジェクト指向言語に比べると、利用環境を選ばず何処でも使えることがjavaの特徴です。

目次

[目次]

1.1 オブジェクト指向言語

構造化プログラミングは複雑なプログラムを部品に分割して,分かりやすく作る手法です。

オブジェクト指向プログラミングは部品の組み合わせや更新が容易になるようにする手法せす。

構造化で大きなプログラムが作れる

ソフトウエアの行数が数十行程度のうちは計算機への命令を順番に書いただけのプログラムで十分です。従って、BASIC言語のような命令を順番に書けばプログラムになる言語が便利です。実行の流れを分岐するifの構文と実行位置を変更するgotoの構文があれば、繰り返しの処理も記述可能です。このような単純な仕組みだけで原理的にすべてのプログラムが記述できます。

しかしプログラムの行数が数百行を超えるようになってくると、人はプログラムの動きを正しく把握できなくなってきます。プログラムは1文字の間違いでも正しく動きませんからこれは大問題。特に、gotoが多用されたプログラムは数十行のプログラムでも理解できないものになりがちです。

大きなプログラムを作るための工夫の一つが構造化です。

実行の流れを解り易くする

ifgotoで、繰り返しや分岐の制御構造は全て書けます。しかし、その書き方はプログラマによって多様に変化し、他人には分岐や繰り返しの範囲が分かりにくいものになりかねません。そこで、構造化プログラミングでは実行の流れを解り易くするために、while文やfor文で繰り返しの書き方を規格化し、gotoで書くのは止めることが提唱されました。

※それでも残ったgotoの使い方として次のようなものが在り、C言語にはgotoが残されています。

1)多重の繰り返しからの脱出:
while文などの繰り返しから脱出する場合breakが用意されているのですが、これは1重の繰り返しから出ることは出来ても、入れ子になった2重の繰り返しから出ることは出来ません。この場合はgotoを使って一度に2重の繰り返しから出ることが可能です。これに対してjava言語ではラベルを使ったbreakで多重の繰り返しから一度に抜けられるので、そもそもgotoは使えない規則になっています。

2)例外処理:
プログラムの基本の流は短く解り易いものにし、基本の流れから分岐する例外処理は別のところに纏めて書いて、基本の流れからgotoで繋ぐといった使い方です。しかし、java言語では例外処理についても専用の構文を用意しています。

分岐や 繰り返しの制御構造が一目でわかるような構文を用意したことで、プログラムの実行の流れは理解しやすくなり、数十行のプログラムなら間違いなく作れるようになりました。しかし、人が数百行のプログラムを作るのが難しいことに変わりはありません。

短いプログラムに分割する

長いプログラムの中に同じような処理が複数含まれることがあります。この同じ処理を括り出して一つのサブプログラムとし、メインのプログラムの数か所から同じサブプログラムを呼び出して使えば、全体のプログラムを短くできます。

プログラムの合計の長さは短くならなくても、プログラムの中の纏まった処理ごとにサブプログラムとし、メインプログラムはサブプログラムを順番に呼び出すだけにすれば、個々のサブプログラムは数十行の短いものにできます。

このような分割で注意しなければいけないのは、各サブプログラムを作るときに他のプログラムを見る必要がないようにすることです。そのためには、サブプログラムに渡される入力データと、処理結果として返す出力データが十分に定義されていることが要件になります。サブプログラムの外部との関係を入出力のみにすることが大事です。

※sin関数の値を計算するサブプログラムなら、入力は実数:θ、出力はθラジアンに対するsin(θ)と定義すれば、関数値の計算方法は外部との関係を考えずにプログラムを作れます。これに対して、データを読み込むサブプログラムでは何所から、どんな形式のデータを読み込んで、何処へどんな形式で格納するのかが解らないとサブプログラムを書けません。この場合は色々な入出力の定義が考えられます。C言語の標準関数scanfの様な実装も一つの方法です。

構造化分析と設計の手法ではデータフロー図(DFD)とデータ辞書が使われます。DFDは処理を表す円と、入出力データを表す線で構成される図です。

 大きな処理はその内部を複数の処理に分けて詳細なDFDとしていくことで単純な処理にまで分解 します。

ここで、各処理の入出力データはデータ辞書に登録し、データ定義を明確に行います。各処理が何を行うかはミニ仕様書として文書化します。何(what)を行うかは決めますが、どのように(how)行うかの手順は決めません。

後は、各ミニ仕様書とデータ辞書を見て各サブプログラムを実装し、それを全体のDFDに従って繋げば目的のプログラムが完成するはずです。

※参考文献 「構造化分析とシステム仕様」トム・デマルコ著 高梨智弘/黒田純一監訳 日経BP社

※ここでデータと処理が異なる扱いをされていることが、さらに大規模なプログラム開発では問題になってきます。

構造化言語

大規模プログラムであるOSの開発に使うためにC言語は造られました。C言語はサブプログラムを規格化した関数を言語の 基本構造としています。データについても構造体を用意して複雑なデータ構造を定義できます。

C言語の関数は関数名、引数並び(入力)、戻り値(出力)のみが呼び出す側に公開されています。呼び出す側から関数内部の実装を見ることは出来ません。実装を更新しても、関数を呼び出す側を変更する必要はありません。つまり、プログラムを作るとき呼び出す関数の実装は知らなくてもいいようになっているので、関数の実装部分の更新は容易です

※関数は実装の違いを捨象(しゃしょう)することで抽象化されているので更新が容易。しかし、大域変数を参照する等の副作用のある実装を行うと抽象化は不完全になる。

※参照する(refer) ここで「変数を参照する」は変数の値を読み出したり、書き換えたりする意味で使っています。「関数を参照する」は関数を実行するの意味で使います。変数も関数もメモリー上の場所で区別されているだけなので、メモリー上の場所を参照するとはメモリーの値をデータとして読み書きするか、プログラムとして実行するかです。

C言語には複数のプログラマが分担して開発するための分割コンパイルとリンクの仕組みが用意されています。 各サブプログラムを分担して作成し、結合して一つのプログラムにまとめることで大規模なプログラムが作れます。

※関数の入力に対する出力が定義されていれば、その関数が使われる場面を知らなくても関数のプログラムが作れます。だからこそ、大勢で分担してプログラムを作れるのです。

構造化のみでは更新と再利用が難しい

大規模で複雑なソフトウエアを1から設計して作り上げることを可能にするため、構造化分析や設計を行い、構造化言語でソフトウエアを実装できるように成りました。しかし、長期間運用すると時代の要求に合わせたソフトウエアの更新が避けられません。あるいは、既存のソフトウエアを組み合わせて、もっともっと複雑なソフトウエアを作りたいといった要求も出てきます。ソフトウエアが大規模になるほど、更新と再利用が重要になります。

構造化されたプログラムを更新する場合に、特に問題になるのはデータ構造です。データ構造を更新する場合、そのデータ構造を使っている全ての関数を見つけて変更することが必要かもしれません。何かを変えたときに、その影響が及ぶ範囲を狭くすることが更新の手間を減らす上で重要です。しかし、データと処理を別々に構造化したプログラムではデータ構造の更新が広範囲に影響を与えるのを防ぐことができません。

※データ形式が更新されたとき、データ辞書の更新は容易ですが、少なくとも入出力や内部処理で更新されたデータ形式を使っている関数は全て更新が必要です。

再利用についても、C言語のprintf 関数のように1つの関数で目的が達成できるなら再利用するのは容易です。しかし、より複雑で大規模なGUIの関数ライブラリーを利用する場合、その中の1つの関数だけでは利用目的を達成できず、複数の関数を適切な手順で呼び出す必要があったりします。GUIを実現する仕組みと関数の役割を学習することが必要で大きな負担になります。 GUIの関数ライブラリーのように再利用を考えて作られたものでも、利用するのは簡単ではありません。

※C言語で関数を順番に呼び出す例としては、ファイルを利用する標準入出力関数があります。まずfopenを実行し、そのあとでfscanfやfprintfで読み書きし、最後はfcloseを忘れずに行います。このあたりはjavaでも似たような煩わしさは残ります。

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

オブジェクトと呼ばれる変数と関数のまとまりを作る考え方があります。オブジェクトは変数と関数をまとめ外部からの参照に対しては参照制限を行います。この参照制限をカプセル化と呼びます。 カプセル化により、オブジェクトを利用する側はその 参照許可の部分にしか触れられません。 参照できない部分はカプセル内で適切に利用され、外からは知る必要のない部分とします。

例えば、データとこれを読み書きする関数をまとめてカプセル化し、データは非公開とし関数のみを参照可とします。内部データの構造を変えても更新が必要なのは読み書きする関数の実装部分のみです。内部データを増やして、新しい読み書き関数を追加したとしても、これまで使ってきた古い読み書きの関数が今まで通り使えれば他へ影響は与えません。データの更新も楽になります。

プログラムをオブジェクトに分割し、オブジェクトが互いに相手オブジェクトの機能を呼び合う形にプログラムを作る手法をオブジェクト指向プログラミングと呼びます。C言語でオブジェクト指向プログラミングを行うことは可能です 。しかし、オブジェクトを作る標準的な仕組みが用意されていない点やカプセル化の機能が弱いなどで現実的ではありません。

オブジェクト指向言語

オブジェクト指向プログラミングを想定した言語が幾つか有りますが、オブジェクトの作り方は1つではありません。オブジェクトを直接プログラムとして記述する言語。基本的なオブジェクトが用意されていて、プログラムでは既存オブジェクトの複製をつくり、中身の追加を行って目的のオブジェクトを作り出すタイプの言語。あるいは、作りたいオブジェクトを生成する雛形を記述し、実行時に、この雛形から目的のオブジェクトを生成をするタイプの言語などが在ります。ここでは雛形を記述するタイプのjava言語を学ぶことにします

※java言語を使えばオブジェクト指向のプログラミングが容易になるだけで、java言語を使ったからといってオブジェクト指向プログラムになるわけではありません。

※javaはクラスベースの言語と呼ばれる。java言語ではオブジェクトの雛形を持ったクラスをソースコードで記述する。オブジェクトはクラスに記述された雛形に従ってプログラム実行中に生成される。クラスを持たずオブジェクトを直接記述する言語や、既存オブジェクトを複製したり中身を追加したりしてオブジェクトを生成するプロトタイプベースの言語などもある。
 実際はオブジェクト指向言語を明確に分類できるわけではありません。java言語でも雛形を記述しないクラスで直接オブジェクトを記述したりもできます。プロトタイプベースと言われるjavascriptがクラスベースの機能も持っていたりもします。

 

まとめ

他人の作った大規模なプログラムを自分のプログラムの中で部品として使うことが、オブジェクト指向プログラミングによってようやく現実的に可能となりました。この講義ではオブジェクト指向プログラミングをjava言語を通して具体的に学んでもらうことにします。

※GUIの様な複雑な機能を持つプログラム部品群もオブジェクト指向言語を用いてクラスライブラリとして用意する事で、使いやすいものになりました。この他にも通信、マルチメディア、データベー スなどさまざまなクラスライブラリが提供されています。

プログラミング言語の分類を表にしておきます。

言語 制御構造 構造化 オブジェクト指向
初期の言語
FORTRAN
BASIC
ifとgotoで自由な実行制御。
サブルーチンや関数を用意
近年、
構造化も取り入れている
近年、
オブジェクト指向も取り入れている
構造化言語
C
Pascal
if-else,while、for文で分岐や繰り返しの制御構造を標準化。
 C言語にgotoは残っているが使うことはまれ
関数としてサブルーチンを標準化。
構造体としてデータ型を階層化して定義可能。
オブジェクト的なものを書くことは可能だが、書き方が標準化できない。カプセル化の機能も不足している
オブジェクト指向言語
Smaltalk
C++、C#
java
javascript
javaでは多重繰り返しからの脱出や例外処理の構文を用意した。gotoは使えない。
オブジェクとして関数とデータをまとめる標準化された基本構造を用意。
 オブジェクト内容への参照制限で実装の違いを見せないようにするカプセル化が行える。

[目次]

1.2 Java言語発表からの経緯

Java言語は計算機ネットワーク社会で使うことを考慮して Sun Microsystems, Inc で作られたオブジェクト指向言語で1995年に発表されました。

2009年にSunはOracleに買収されjavaの開発環境jdkはOracleにより継続して提供されています。

※上記はWikipedia「java」を参考にしています

※ jdk(Java Development Kit
はコンパイラなどを含む開発キット
javaのダウンロードサイトではJDK(java開発環境)やJRE(java実行環境)が無償でダウインロードできる。ここでJREは実行環境のみでコンパイラ等の開発環境は含まない

javaは利用目的に応じて幾つかのEditionで提供されている

[目次]

1.3 WRITE ONCE, RUN ANYWHERE

一度コードを書けばどこでも動くということです。ネットワーク上には様々なハードやOSの計算機が繋がれています。そこでネットワークで利用するプ ログラムは機種やOSに依存しないで同じように動くことが望まれます。

C言語のプログラムを作ったとしましょう。ソースコードをWindows上のコンパイラで翻訳し機械語の実行可能コードを作れば Windowsでプログラムが実行できます。このプログラムの開発環境はWindows上と言うわけです。ここで実行可能コードをそのまま 色々な計算機に持っていき動かせるでしょうか?使っているCPUなどハードウエアが異なり機械語が違う と動かないのは確実です。ハードウエアが同じでもOSが違っていると動かいことが多いでしょう。インターネットには様々な計算機がつながっているのでこれでは困ります。

では、ソースコードを持って行き、目的の計算機のCコンパイラで翻訳し実行可能コードを作れば動くでしょうか? HelloWorldと打ち出すだけのプログラムなら問題なく動くでしょう。しかし、ウインドウやボタンなどを使うプログラムではコンパイルやリンクで失敗するでしょう。多くの場合、OSやGUIのライブラリーなど実行環境に合わせてソースコー ドを書き直すことが必要です。

中間言語方式

インタープリタ interpreter

LISPやBASICの様にソースコードを1文づつ解釈し実行するシステムをインタープリタと言います。プログラムを 一文づつ実行できるために、プログラムの動作を確認しながら実行できる利点があります。
しかしこの手法はソースコードの文の解釈に多くの処理時間がかかるためにプログラムの実行が遅いという欠点があります。そこで最近はLISPやBASIC等の言語も下記 コンパイラや中間言語方式が使われる様になっています

※シェルスクリプトやJavascriptのようなスクリプト言語処理系もインタープリタの例である。

コンパイラ Compiler

C言語の様にソースコードをまとめて機械語に翻訳し実行ファイルとして保存するシステムをコンパイラと呼びます。実行ファ イルはコンパイラ無しで単独で実行可能です、さらに機械語に翻訳済なので、実行は高速です。  しかし、この実行ファ イルは違う機械語の計算機ではもちろん動きません。機械語が同じでも,場合によってはOSが違うと動きません。

中間言語(interlanguage)方式

ソース コードを中間言語コード(仮想の機械語)に翻訳するコンパイラと中間言語コードを実行するインタープリタ(仮想機械)を組み合わせた方式です。Javaの システムでは以下の順番で処理され、実行が行われます。

Bytecode Compilerでソースコードをバイトコード(Bytecode)と呼ばれる中間言語コードにコンパイル する

JavaVM(Java Virtual Machine)と言われるインタープリタでこのバイトコードを実行する

インタプリタは遅いと言われますが、Javaのバイトコードは仮想の機械語で、ソースコードを直接インタプリタで実行するよりは高速に解釈と実行が行えます。さ らにJavaVMではバイトコードを実行環境の機械語にまとめてコンパイルしてから実行するJIT(ジャストインタイムコンパイラ)や実行速度向上に重要な部分を選んでコンパイルし実行する HotSpotなどの手法が使われることで、実行速度は改善されています。

計算機の機種やOSごとにBytecode CompilerやjavaVMを用意することで、ソースコードとバイトコードは同じも のが機種やOSによらず使えます。Java言語は広く普及し、利用者も多いことから主要な機種とOSに対してコンパイラとjavaVMおよび標準クラスライブラリー(※)が用意されていま す。

※ウインドウやボタンと言ったGUIの部分はOSによっても違いが出てしまいます。この為、実行環境に応じたJavaVMだけでなく標準クラスライブラリーも用意しなければなりません。バイトコードを実行するために、実行環境ごとのJRE(javaVM+標準クラスライブラリー)が提供されています。 JDKはJRE+バイトコードコンパイラ等の開発環境です。

 

※関数型言語ScalaのようにjavaVMで実行する言語も現れてきました。javaVMがjava以外の言語の実行環境としても重要になり始めています。

データ型の規格統一

/*C言語の例*/
int i;
for(i=0;i<100000;i++){....}

C言語の様に基本データ型さえも計算機環境に依存する言語では、このfor文のプログラムもint型が4バイトなら正常に実行されますが、 2バイトの場合は無限ループになってしまいます。

Java言語ではこの様なことが無いように基本データ型は規格統一されて実行環境には依存しません。

※今のCPUは4バイトの整数演算を用意するものが多いので,C言語のint型は4バイトのことが多い。しかし,C言語はCPUが2バイト整数演算しか用意していないなら,int型を2バイトの整数とすることを許容します。

標準ライブラリ

これまでのGUI(グラフィカル・ユ-ザ・インタ-フェ-ス)を利用するプログラムの場合は,OSや利用するGUIのライブラリーが違うとソースコードさえも同じものは使えませんでした。 たとえ同じWindows上のプログラムでも、開発環境ごとにGUIのライブラリーが異なり使い方も違うため、同じソースコードが使えないのが当たり前でした。UNIXやMacOSでもそれぞれに個性的なGUIの枠組み を採用していますから、WindowsのプログラムをMacOSに移植する作業は大変です。

この問題を解決するには,機種やOSごとに同じ仕様のライブラリを用意する必要があります。

Java言語ではGUIだけでなく通信、マルチメディア等の標準ライブラリを実行環境ごとに用意しています。これにより同じバイトコードのプログラムを多様な実行環境で実行できます。

誰でも何処でも

java言語は現在、http://www.oracle.com/technetwork/java/index.html  から実行環境(JavaVMとライブラリ)や開発環境(+javaコンパイラなど)が無償でDownloadできます。さらにライブラリのソースコードなど も公開され、誰もが使いやすい条件が整っています。WebブラウザからJavaVMを利用することが可能で、javaで作られたappletプログラムを実行 できます。これほど何処でも実行できるプログラム言語は他にありません。

さらに多くの人が利用することを考慮して 国際化 (internationalization) も実現しています。Unicodeの採用と各種文字コードとの変換機能が用意され、変数や関数の名前に日本語名を使うことさえ可能です。

堅牢性とセキュリティ−

javaではネットワーク上のプログラムを自分の計算機で安全に実行できるような考慮がされています。プログラムのミスを少なくするために、javaではC/C++言語の便利ではあるが危険な機能:ポインタを制限し参照型としてのみ使えるようにしました。メモリー開放も自動で行いプログラムが暴走する危険性を減らしています。Javaプログラムが使える資源についても認証機能を用いて設定が行えます。例えばWebブラウザ上でのJavaプログラムの実行ではプログラムのハードディスクへのアクセスを禁止するなど悪意のあるプログラムの実行を困難にしています。

※javaでも危険な不正なプログラムは作れます。絶対安全ではない。

  

[目次]

1.4 Javaプログラムの実行形式

javaプログラムは通常のApplicationプログラムの他にWWWブラウザの上で実行されるAppletプログラムやWWWサーバ(HTTPサーバ)の上で実 行されるServletプログラムのなどの複数の実行形式が用意されています。

  1. Application
    JavaVMによりWindowsや UNIXなどのOS上で実行されます。特にセキュリティー等の制限は無く、通常のプログラムと同じです。 
  2. Applet
    WWWのページの中にHTMLのタグでAppletプログラムの呼び出しを挿入できます。WWWブラウザはタグに指定されたURLからクラスファイルをダウンロード し実行します。クライアントのHDDを読み書きできない。クラスファイルを提供したWWWサーバとしか通信できない。のようなセキュリティー上の制限があります。
    (近年のブラウザはセキュリティーを重視してAppletの実行を制限するようになった)
  3. Servlet
    Tomcat等のServletをサポートするWWWサーバ上にクラスファイルを置き、サーバからの呼び出しに応じてサーバ側で実行されます。一度呼び出さ れるとWWWサーバに常駐してクライアントの要求に応じてHTMLページを作成し、CGIに似た機能を実現します。WWWとデータベースを連携したサービ スの実装などに利用され、Servletを作りやすくするJSP等の仕組みとともにサーバーサイドアプリケーションに使われています。

[目次]


[ prev | next | index ]