NetBeansあけましておめでとうございます。今年の5月で平成が終わってしまいます。聞いたことはあるけど実際にプログラムを組む上で使った記憶がないのでこれで遊んでみよう。ドキュメントには下記のように記されてます。メモリー要求に応じてガベージ・コレクタの判断でクリアされるソフト参照オブジェクトです。ソフト参照は通常、メモリー・センシティブなキャッシュを実装するために使用されます。ある時点で、オブジェクトがソフト到達可能であると、ガベージ・コレクタが判断したとします。その時点で、ガベージ・コレクタは、そのオブジェクトへのソフト参照すべてと、強参照のチェーンを経由してそのオブジェクトに到達できるような、ソフト到達可能なほかのオブジェクトへのソフト参照すべてを原子的にクリアすることを選択できます。同時にまたはあとで、ガベージ・コレクタは、参照キューに登録されているそれらの新しくクリアされたソフト参照をキューに入れます。ソフト到達可能なオブジェクトへのすべてのソフト参照は、仮想マシンがOutOfMemoryErrorをスローする前にクリアされていることが保証されています。ない場合、ソフト参照がクリアされる時点、またはさまざまなオブジェクトへの一連のソフト参照がクリアされる順序に制約はありません。仮想マシンの実装は、最近作成されたソフト参照または最近使用されたソフト参照をクリアしないことが奨励されます。このクラスの直接のインスタンスは、単純なキャッシュを実装するために使用できます。このクラスまたは派生したサブクラスは、より洗練されたキャッシュを実装するために、もっと大きなデータ構造でも使用できます。ソフト参照のリファレントが強到達可能であるかぎり、つまり実際に使用されているかぎり、ソフト参照はクリアされません。このため、たとえば洗練されたキャッシュは、エントリへの強いリファレントを維持することで、もっとも新しく使用されたエントリが破棄されることを防ぎ、ほかのエントリはガベージ・コレクタの判断で破棄されるようにできます。プログラムが止まってしまうことがない。クラスにはコンストラクタが2種類あります。referent)指定されたオブジェクトを参照する新しいソフト参照を作成します。新しい参照は、どのキューにも登録されません。q)指定されたオブジェクトを参照し、指定されたキューに登録されている新しいソフト参照を作成します。参照が登録されるキュー。登録が必要ない場合はnullメソッドは一つだけあります。get()参照オブジェクトのリファレントを返します。プログラムまたはガベージ・コレクタによって、この参照オブジェクトがすでにクリアされている場合、このメソッドはnullを返します。戻り値:この参照が表すオブジェクト。この参照オブジェクトがクリアされている場合はnullもの凄く質素なクラスですね。言うことでさっそくお試しプログラムを組んでみました。1024];}}}無駄にメモリーを消費するインスタンスを1000個作っているだけです。使って賢いガベージ・コレクタの力で完走させようというものです。プログラムの実行結果は次のようになりました。8964プログラムが終了するまで1分8秒もかかった。私の7年前のパソコンが壊れたのかと思ってしまった。プロファイラでどんなかんじなのか確認してみました。回数、累積時間が長いような気がする。こんなものなのかなぁ・・・あっ、なにかプログラムに問題があるのかもしれない。試して比較してみるしかない。初日(12月4日)です。Jigsawのお勉強をしています。(^_^;)今回はJavaFXを使ってみます。そんなJavaFXですが正式リリース前からさらにリリースされてからもいろいろありました。現在はJavaにバンドルされていません。正確にはいろいろなところからJDKが提供されているのでひょっとしたらJavaFXをバンドルしたJavaがあるのかもしれません。今回はOpenJDKとOpenJFXを使います。11でjavafx.scene.control.Spinner<T>クラスにほんの少し優しい変更が追加されたのでそれを試してみました。8の750ms固定だったのが自由に変更できるようになりました。InitialDelayとRepeatDelayが設定可能となります。Spinnerについて少しだけ復習しておきましょう。SpinnerのAPIドキュメントに下記のように書かれています。順序付けられたシーケンスからユーザーが数値またはオブジェクト値を選択できるようにする単一行のテキスト・フィールド。通常、スピナーはシーケンスの要素間を移動するための小さな矢印ボタンのペアを提供します。キーボードの上/下矢印キーでも要素間を自由に移動できます。ユーザーがスピナーに直接(有効な)値を入力することもできます。UIコントロールのようにObservableListデータ・モデルを使用せずに、wrappingなどの機能や、より単純な’無限’データ・モデルの仕様(SpinnerValueFactory)を使用できるためです。Spinnerのシーケンス値はSpinnerValueFactoryで定義します。propertyを使用して変更できます。JavaFXには、次に示す一般的なタイプのSpinnerValueFactoryクラスが用意されています。•SpinnerValueFactory.IntegerSpinnerValueFactory•SpinnerValueFactory.DoubleSpinnerValueFactory•SpinnerValueFactory.ListSpinnerValueFactorySpinnerには、Spinnerの現在のvalueの表示および変更を行う、editorと呼ばれるTextField子コンポーネントがあります。propertyをtrueに設定すると、入力を受け入れることができます。propertyに対する変更をリスニングすることにより、値ファクトリとの同期を保ちます。ユーザーがeditorに表示された値を変更した場合、Spinnerのvalueとeditorの値が異なってしまう可能性があります。モデルの値をeditorの値と同じにするには、ユーザーが[Enter]キーを使用して編集をコミットする必要があります。APIドキュメントによると一般的なタイプのSpinnerValueFactoryクラスと使ってSpinnerインスタンスを作成できると書かれていました。factoryを設定する場合Spinnerインスタンスを作成するのは容易にできることが確認できたので次はSpinnerの定数フィールド値を使ってスタイルの設定方法を調べてみます。STYLE_CLASS_ARROWS_ON_LEFT_HORIZONTAL水平方向(左向きと右向き)の矢印がSpinnerの左側に配置されます。STYLE_CLASS_ARROWS_ON_LEFT_VERTICAL垂直方向(上向きと下向き)の矢印がSpinnerの左側に配置されます。STYLE_CLASS_ARROWS_ON_RIGHT_HORIZONTAL水平方向(左向きと右向き)の矢印がSpinnerの右側に配置されます。STYLE_CLASS_SPLIT_ARROWS_HORIZONTALSpinnerの左側に減分矢印、右側に増分矢印が配置されます。STYLE_CLASS_SPLIT_ARROWS_VERTICALスピナーの幅全体にわたって上下に伸びた矢印が配置されます。何も指定をしない場合はデフォルトの垂直方向(上向きと下向き)の矢印がSpinnerの右側に配置されます。Spinnerインスタンスの作成、スタイルの設定方法が解ったので試してみます。arg0)メソッドでSpinnerの定数フィールド値を追加して設定します。Spinnerの増分、減分の矢印ボタンの配置デザインの設定はこれで可能となりました。Spinnerに表示されている値のアライメントとカスタムフォントを設定してみます。CENTER_RIGHT;”);上の行でカスタムフォントを読み込んでその下の行でSpinnerにそのフォントを設定、テキストのサイズ、文字色、アライメントを設定しています。Spinneのエディタをユーザー入力可能とするspinner.setEditable(true);としてユーザー入力可能としてます。増分、減分のステップ量は変わらずユーザーによって入力された値からの増分値、減分値となります。最大値、最小値を超えることはありません。ここまでのプログラムのソースコードは次のようになります。{launch(args);}}それではSpinnerにInitialDelayとRepeatDelayを設定するプログラムを組んでみます。(openjfx-12-ea+2)を使ってみます。モジュラjarを作ってモジュール化します。jlinkで配布用にカスタムJREをバンドルしたアプリケーションを作成します。10.0-vc4を使ってお気楽に組もうとしたがこのバージョンには未対応なので古典的なツールを使いました。Devでプロジェクトをビルドし、jlinkでカスタムJRE組み込みアプリケーションの作成はできました。エラーバッジの嵐のエディタは心が痛みます。10.0-vc4を使って下記ファイルを作成します。なんかは対応していた。なんかは対応していた。included.");}}}プロジェクトの構成は下図のようにします。カスタムフォントを使うのでお気に入りのフォントをご用意ください。VMオプションをつけます。11からJavaFXはバンドルされなくなったのでそれらライブラリをダウンロードしてコンパイル、実行時にモジュールパスを指定します。JavaFXはこちらから入手できます。jmodsがあります。jmodsが必要となります。オプションでbin/IncludeeJavaFXディレクトリにコンパイルによって作成されるクラスファイルが格納されるようにしています。SDKのパスを指定します。–add-modulesオプションでアプリケーションで必要とされるモジュールを指定します。FXMLDocument.fxmlはコンパイルを実行しても出力ディレクトリbin/IncludeeJavaFXには移動、コピーされないので存在しません。FXMLDocument.fxmlをコンパイルして作成されたクラスファイルのある場所にコピーします。フォントを格納しているresourcesディレクトリもコピーします。プロジェクトの構成は下図のようになります。それでは実行してみましょう。VMオプションを忘れずに。–module-path、–add-modules、–moduleオプションも必要です。コンパイルされて実行できました。思いきや何やら妙な警告がでました。オプションをあたえます。12のリリースまでには修正されるのかな?それではこのプログラムをモジュラjar化してみます。modsディレクトリを作成してそこにモジュラjarを格納します。–module-versionでこのモジュールのバージョンを設定します。実行時メインクラスの指定をしなくていいように–main-classオプションを使ってメインクラスを指定してアプリケーションエントリポイントを設定します。モジュラjarがちゃんとできたか確認します。問題無さそうなのでプログラムを走らせてみます。SDKのパスを指定します。–moduleオプションはメインクラスの指定を省力できるようにしたのでモジュール名だけで実行できます。モジュール名/モジュールのメインクラス名とアプリケーションエントリポイント指定しなければいけません。IncludedJavaFX/jp.yucchi.includedjavafx.IncludedJavaFXとします。アプリケーションのモジュール化に成功し、ちゃんと動くことが確認できました。最後にjlinkで配布用にカスタムJREをバンドルしたアプリケーションを作成します。includedjavafx-imageディレクトリを作成しそこに成果物を格納します。–module-pathオプションでJDKとJavaFXのモジュールを指定します。jmodsのパスを指定することに注意してください。–add-modulesオプションでこのアプリケーション自体を指定します。–launcherオプションを次のように設定します。<コマンド名>=<モジュール名><メインクラス>–outputオプションで出力先を設定します。jlinkによって作成されたランチャーファイルにVMオプションを記述します。これを忘れると少し焦ります。(^_^;)動きましたね。JavaがインストールされてないPCでも動くことを確認しました。(Linux)ただしWindowsでは動きません。Windowsで動く配布用アプリはWindowsで作成しなくてはいけないようです。肝心のことを忘れていました。上のGifアニメで増分、減分ボタンを押しっぱなしにしている時のSpinnerの更新時間に注目してください。メソッドで押し続けて最初に更新される時間を設定しています。このプログラムでは解りやすくするために1500ミリ秒に設定しました。500ミリ秒と設定しました。750ミリ秒に固定されていて変更することができなかったので少しうれしいアップデートです。JavaFXになってほしい。Jigsawにもほんの少しだけ慣れてきたけど難しいですね。モジュールの依存関係を調べるのがお手軽にできるツールがあればいいのだけど・・・jdepsは万能ではないので落とし穴に落ちます。)今回のプログラムではFXMLを利用しています。JavaFXでGUIの構築にはとても便利です。javafx.fxml;とrequiresモジュールディレクティブ設定します。ところがそれだけではjava.lang.reflect.InvocationTargetExceptionが投げられます。FXMLを利用したJavaFXアプリケーションではjavafx.fxmlモジュール側からこのプログラムのFXMLのコントローラークラスに対してリフレクションによるアクセスがあります。モジュールのカプセル化はリフレクションにも適用されるからです。9より前はリフレクションを使えばパッケージ内の全てのクラスやクラスの全てのメンバーにアクセスできました。リフレクションは開発者の本意と関係なくカプセル化を破壊することが可能です。Jigsawでは強力で繊細なカプセル化が提供されています。デフォルトでは外部モジュールからモジュール内のクラスにアクセスすることはできません。外部モジュールからアクセスできるのはexportsされたパッケージの公開クラス、公開メンバだけなのです。非公開なメンバへのアクセスは外部モジュールから禁止されています。いった所でもモジュール化のメリットである依存性、公開範囲の制限が絡んでくるんですね。このリフレクションによるjavafx.fxmlモジュール側からのアクセスを許可する必要があります。それにはopens...toモジュール・ディレクティブを設定します。javafx.fxml;とopensモジュールディレクティブを付け加えるだけです。module-info.javaにこのモジュールディレクティブを加えることによって実行時にのみ特定のモジュールに対してパッケージへのアクセスを許可することが可能です。特定のパッケージ内のpublic型(およびネストされているpublic型とprotected型)に対して実行時にのみアクセスできることを指定可能となります。指定したパッケージのすべての型(およびその型のすべてのメンバ)にリフレクションを使ってアクセスすることもできます。9より前のものより開発者には喜ばれるはずですね。なるとjdepsのような依存性を解決する強力なツールの必要性が求められます。そのうち統合開発環境なんかに乗っかってくることを期待します。超スローペースですがゆっくり慌てず三歩進んで二歩下がるような感じでもう暫く進めていこうと思っています。Jigsawでモジュールを作成する」の写経をおこなってみました。Jigsawで実現される機能の確認は同様にしました。元記事で解説されているようにモジュールの定義は次のようになっています。JARファイルにモジュール名が付いて依存性や公開範囲を記述できるようになったようです。詳しくは元記事を参照してくださいませ。モジュールを作っていきます。プログラムを起動したら挨拶(文字列)を表示させるだけのプログラムです。挨拶を表示させるためのインタフェースとしてGreetingインタフェース、その実装クラスとしてMultilingualGreetingクラスを作成します。実装クラスのMultilingualGreetingクラスは日本語の挨拶か英語の挨拶をランダムに返します。MultilingualGreetingクラスは外部からアクセスされることを避けるようにします。インターフェイスにprivateメソッドが記述できるようになったのは今回は忘れてください。Jigsaw!";}}このアプリケーションをモジュールとするためにmodule-info.javaをトップディレクトリに作成します。jp.yucchi.greeting;とmodule-info.javaに記述されています。これは公開範囲を定義しています。jp.yucchi.greeting.internalパッケージは公開されてないので外部からアクセスすることはできません。それではjp.yucchi.greetingモジュールを使用するモジュールを作成します。Greeting.of();System.out.println(greeting.greeting());}}続いてこちらもモジュールとするためにmodule-info.javaを作成します。jp.yucchi.greeting;と記述しています。これは依存性の定義となります。jp.yucchi.helloと自分自身を公開すると定義しています。Helloクラスのmain()メソッドをコールすることも外部アクセスとなるからです。これでシンプルなお試しプログラムが完成しました。ディレクトリ構造は前回までと少し変更しています。それぞれコンパイルしてみましょう。src/jp.yucchi.hello/classes/module-info.javabinディレクトリを作成してコンパイルされたファイルを配置しました。それでは確認のためにプログラムを実行してみます。うごきましたね!(^_^)それではモジュラーJARとしてパッケージ化してみましょう。.modsディレクトリを作成してモジュラーJARとしてパッケージングし配置しました。一応できているみたいですが正しくできているか念の為に確認します。メインクラスなどの情報に間違いが無いことを確認することができました。依存性の定義にjava.baseモジュールがありますがこれはjava.lang.Objectクラスなどが含まれた必要不可欠なもので全てのモジュールに含まれることになります。jp.yucchi.greeting.internalと表示されています。9からjarコマンドが少し変更されているのでヘルプをみておきましょう。...jarはクラスおよびリソースのアーカイブを作成し、アーカイブから個々のクラスまたはリソースを操作または復元できます。モジュラjarアーカイブを作成する。記号(@)を接頭辞として使用してjarコマンドに渡します。アーカイブ・ファイル名。プログラム・バージョンを出力しますモジュール・ディスクリプタ’module-info.class’が指定のディレクトリのルートまたはjarアーカイブ自体のルートにある場合、アーカイブはモジュラjarです。‘–hash-modules’および’–module-path’。ロング・オプションへの必須またはオプションの引数は、対応するショート・オプションに対しても必須またはオプションになります。Jigsawの影響でコマンドが増えていますね。(当たり前か・・・)最後にこのプログラムを実行してみます。jp.yucchi.helloアプリケーション・エントリ・ポイントを設定したモジュールのモジュールパスとモジュール名を指定してjavaコマンドによって実行します。今回はモジュラーJAR作成時にアプリケーション・エントリ・ポイントを指定してますのでこのように実行できます。モジュラーJAR作成時にアプリケーション・エントリ・ポイントを設定してない場合は次のように実行します。jp.yucchi.hello/jp.yucchi.hello.Helloモジュールのモジュールパスの指定はおなじです。モジュール名/モジュールのメイン・クラス名とアプリケーション・エントリ・ポイント指定しなければいけません。javaコマンドのヘルプも確認しておきます。<jarfile>、-mまたは–module<module>/<mainclass>に続く引数は、メイン・クラスへの引数として渡されます。