この授業では、アプレットを使ってお絵描きをしました。 本当は、アプレットはもっと色々なことができます。 楽しいアプレットが埋め込まれたホームページは非常に魅力的です。
ここで、アプレットもれっきとしたプログラムであること、そしてそのホームページを訪れると、アプレットが転送され、あなたのコンピュータの上で動くことを思い出してください。 悪意のある人の作ったアプレットが、あなたのコンピュータのファイルを消したり、個人情報を盗んだりしないのでしょうか。
この心配への答えは、「アプレットにできることは制限されていて、悪事を働くのは困難である。」です。 以下では、個人情報(具体的にはユーザ名)がアプレットで取り出せないことを確かめます。
はじめに、スタンドアロン・アプリケーションで、Javaシステムに関する情報(システム・プロパティとよばれます)を取り出します。 次のプログラムは、Javaシステムが動いているOSの名前を表示します。
/* 1*/ class PropertyTest1 { /* 2*/ public static void main (String[] args) { /* 3*/ String s = System.getProperty("os.name"); /* 4*/ System.out.println(s); /* 5*/ } /* 6*/ }
b00a001@Ampere:~/java% java PropertyTest1 Solaris b00a001@Ampere:~/java%
3行目の System
クラスのクラスメソッド getProperty
がシステム・プロパティを取り出します。
引数はシステム・プロパティの名前(文字列)です。
OSの名前はos.nameで、ユーザ名はuser.nameです。
(システム・プロパティは他にもあります。)
したがって、3行目の "os.name"
を "user.name"
に置き換えますと、ユーザ名(この場合はb00a001)が表示されます。
次に、同じことをアプレットで行ないます。
7行目の Graphics
クラスのインスタンスメソッド drawString
はアプレットで文字列を描画するものです。
この第2引数と第3引数は、文字列イメージの左下の座標です。
/* 1*/ import java.applet.*; /* 2*/ import java.awt.*; /* 3*/ /* 4*/ public class PropertyTest2 extends Applet { /* 5*/ public void paint (Graphics g) { /* 6*/ String s = System.getProperty("os.name"); /* 7*/ g.drawString(s, 0, 20); /* 8*/ } /* 9*/ }
<applet code="PropertyTest2.class" width="200" height="100"> </applet>
b00a001@Ampere:~/java% appletviewer PropertyTest2.html & b00a001@Ampere:~/java%
Applet Viewer |
Applet |
Solaris |
applet started |
さて、"os.name"
を "user.name"
に置き換えて、スタンドアロン・アプリケーションのときのようにユーザ名が取り出せるでしょうか。
試してみますと、アプレット・ビューアは起動しますが、ユーザ名は描画されません。
その代わり、端末エミュレータにエラーメッセージが出力されます。
セキュリティ上の問題があるのでアプレットを停止するということです。
b00a001@Ampere:~/java% appletviewer PropertyTest2.html & *** Security Exception: properties *** sun.applet.AppletSecurityException: security.properties (中略) b00a001@Ampere:~/java%
注意:
設定によっては、アプレット・ビューアでユーザ名が描画されてしまいます。
(環境変数 CLASSPATH
が関係します。)
この場合は、WWWブラウザでアプレットを表示してください。
Javaは高い信頼性を持つ言語です。 この信頼性を支える仕組みの一つに、ガベージ・コレクション(garbage collection)があります。
コンピュータのメモリ領域は有限ですので、大規模なデータ処理を行なう際には、不要なデータを破棄し、メモリを開放する必要が生じます。 多くのプログラミング言語では、この作業はプログラマの責任で行ないます。 しかし、不要なデータをいつまでも残してメモリ不足を引き起こしたり、誤った開放によって必要なデータを失ったりというバグを導きやすいのも事実です。
Javaは、この面倒な作業を自動的に行ないます。 これがガベージ・コレクションです。 ガベージ・コレクションでは、誰からも参照されないデータを不要なものと見なし、機械的にそれを検知してメモリを開放します。 機械的な部分で多少時間がかかりますが、バグの要因が減った分、信頼性の高いプログラムが書けるのです。
ガベージ・コレクションの働く例を以下に示します。 ここでヒープ(heap)とは、プログラムの実行中に確保されるメモリ領域のことです。
次のプログラムは、単にメモリを消費するものです。
Java言語では、int型のデータは4バイトと決まっていますので、2次元配列 a
の消費するメモリは8×65536×4バイト、すなわち2MBです。
/* 1*/ class GCTest1 { /* 2*/ public static void main (String[] args) { /* 3*/ int i; /* 4*/ int[][] a = new int[8][]; /* 5*/ for (i = 0; i < 8; i++) { /* 6*/ a[i] = new int[65536]; /* 7*/ System.out.println(i); /* 8*/ } /* 9*/ } /*10*/ }
Javaインタプリタは、デフォルトでは十分な(16MB)最大ヒープ領域を持ちますので、このプログラムは問題なく実行できます。
b00a001@Ampere:~/java% java GCTest1 0 1 2 3 4 5 6 7 b00a001@Ampere:~/java%
そこで、ヒープ領域を1MBに制限してみます。
オプションの ms
は初期ヒープ領域、mx
は最大ヒープ領域を表します。
1MBのヒープ領域に2MBのデータは収まりませんので、プログラムは途中でエラーを起こして停止します。
b00a001@Ampere:~/java% java -ms1m -mx1m GCTest1 0 1 2 java.lang.OutOfMemoryError at GCTest1.main(GCTest1.java:6) b00a001@Ampere:~/java%
次に、以下のようなプログラムを考えます。
これは上記のプログラムに似ています。
違いは、あらかじめ5行目で配列 b
を用意しておき、それを8行目で a[i]
に格納しなおすところです。
/* 1*/ class GCTest2 { /* 2*/ public static void main (String[] args) { /* 3*/ int i; /* 4*/ int[][] a = new int[8][]; /* 5*/ int[] b = new int[65536]; /* 6*/ for (i = 0; i < 8; i++) { /* 7*/ a[i] = new int[65536]; /* 8*/ a[i] = b; /* 9*/ System.out.println(i); /*10*/ } /*11*/ } /*12*/ }
配列 b
がありますので、プログラム GCTest2
は GCTest1
よりメモリを消費するように思えます。
しかし、GCTest2
は1MBのヒープ領域で実行できるのです。
b00a001@Ampere:~/java% java -ms1m -mx1m GCTest2 0 1 2 3 4 5 6 7 b00a001@Ampere:~/java%
この現象を理解するには、GCTest2
の7行目と8行目に注目する必要があります。
7行目では、確かに65536要素の配列を生成し、それを a[i]
に格納しています。
しかし、8行目で a[i]
に配列 b
を格納しなおしますので、7行目で生成した配列は誰も参照できなくなります。
誰も参照できないデータは記憶しておく必要がありませんので、Javaインタプリタはその領域を自動的に検知し、他のデータの記憶のために再利用するのです。
レポート(アンケートも含む)の提出に関するスケジュールは以下の通りです。
この授業の成績は、レポートの得点とアンケートの提出(出席点)で決まります。
成績に関して以下のような事情のある人はメールで連絡してください。 できる限り対処します。
情報処理センターのアンケートに答えてください。