24 Nov 2014, 02:23

Ruby の win32ole で Windows GUI アプリのキー操作を自動化する

はじめに

Windows 上のアプリをキーボード操作で自動化したいと考えた.

Ruby の win32ole を利用すれば, 実現できそうなので, 調べた.

Win32ole とは

Windows 版の Ruby には, win32ole というライブラリがある.

これを利用すると, Ruby から Windows のいろいろなアプリを操作できる. (Excel,iExplore などなど…)

Windows アプリにキーを送ることができるので, キー操作で完結するアプリならば, 操作を自動化できる, というわけだ.

以前, Excel の操作で win32ole を利用した.以下, 過去記事参照.

今回は, キーボード操作関連の情報をまとめる.

WSHShell を操作

WSHShell とは, Windows のシェル. これを Ruby から制御する.手順は 2 つ.

  • あるウィンドウをアクティブにできる
  • アクティブなウィンドウにキーコードを送る

事前準備

<div class="outline-text-3" id="text-unnumbered-4">
  <p>
    以下の 2 行で, まずは wsh オブジェクト生成.
  </p>

  <p>
    [sourcecode language=&#8221;ruby&#8221; title=&#8221;&#8221; ]<br /> require &#8216;win32ole&#8217;<br /> wsh = WIN32OLE.new (&#8216;Wscript.Shell&#8217;)<br /> [/sourcecode]
  </p>
</div>

プログラム起動

<div class="outline-text-3" id="text-unnumbered-5">
  <p>
    Run メソッドでプログラムを起動できる.
  </p>

  <p>
    [sourcecode language=&#8221;ruby&#8221; title=&#8221;&#8221; ]<br /> wsh.Run (&#8216;notepad.exe&#8217;)<br /> [/sourcecode]
  </p>
</div>

ウィンドウをアクティブにする

<div class="outline-text-3" id="text-unnumbered-6">
  <p>
    AppActivate メソッドで ウィンドウをアクティブにできる.
  </p>

  <p>
    アプリのタイトルを指定する. 成功すると, ture が返る. 失敗すると, false が返る.
  </p>

  <p>
    [sourcecode language=&#8221;ruby&#8221; title=&#8221;&#8221; ]<br /> wsh.AppActivate (&#8216;Title&#8217;)<br /> [/sourcecode]
  </p>
</div>

ウィンドウにキーコードを送る

<div class="outline-text-3" id="text-unnumbered-7">
  <p>
    SendKeys メソッドで ウィンドウにキーを送る.
  </p>

  <p>
    [sourcecode language=&#8221;ruby&#8221; title=&#8221;&#8221; ]<br /> wsh.SendKeys (&#8216;A&#8217;)<br /> [/sourcecode]
  </p>

  <p>
    詳細な SendKey コードはここにある.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://msdn.microsoft.com/en-us/library/8c6yea83.aspx">SendKeys Method</a>
    </li>
  </ul>
</div>

Sample

notepad

<div class="outline-text-3" id="text-unnumbered-9">
  <p>
    メモ帳起動してなにか書く. Popup メソッドでメッセージ表示.
  </p>

  <p>
    [sourcecode language=&#8221;ruby&#8221; title=&#8221;&#8221; ]<br /> require &#8216;win32ole&#8217;
  </p>

  <p>
    wsh = WIN32OLE.new (&#8216;Wscript.Shell&#8217;)<br /> wsh.Run (&#8216;notepad.exe&#8217;)<br /> wsh.AppActivate (&#8216;無題&#8217;)
  </p>

  <p>
    wsh.SendKeys (&#8216;Hello&#8217;)
  </p>

  <p>
    wsh.Popup (&#8216;Happy Hacking!!&#8217;)<br /> [/sourcecode]
  </p>
</div>

explorer

<div class="outline-text-3" id="text-unnumbered-10">
  <p>
    C:-neraフォルダをコピーして test2 フォルダを作成する.
  </p>

  <p>
    [sourcecode language=&#8221;ruby&#8221; title=&#8221;&#8221; ]<br /> # coding: utf-8<br /> require &#8216;win32ole&#8217;
  </p>

  <p>
    wsh = WIN32OLE.new (&#8216;Wscript.Shell&#8217;)<br /> wsh.Run &#8216;explorer C:\Users\tsu-nera\Desktop&#8217;
  </p>

  <p>
    sleep (3)
  </p>

  <p>
    wsh.AppActivate (&#8216;Desktop&#8217;)
  </p>

  <p>
    # テストフォルダ選択<br /> wsh.SendKeys (&#8216;t&#8217;)
  </p>

  <p>
    sleep (0.5)
  </p>

  <p>
    # コピー & ペースト<br /> wsh.SendKeys (&#8216;^c^v&#8217;)
  </p>

  <p>
    sleep (0.5)
  </p>

  <p>
    # リーネム<br /> wsh.SendKeys (&#8216;{F2}test2{ENTER}&#8217;)
  </p>

  <p>
    # popup<br /> wsh.Popup (&#8216;Copy Success!!&#8217;)<br /> sleep (3)<br /> wsh.SendKeys (&#8216;{ENTER}&#8217;)<br /> [/sourcecode]
  </p>
</div>

23 Nov 2014, 15:29

WordPress の埋め込み gist のスタイルシート (CSS) の設定メモ

はじめに

最近すごく気になってたのだが, ブログでの gist の表示が崩れまくっている ので, 直し方を調べたのでメモする.

以下の過去記事も参照.

CSS の調べ方

要素を調べる

ブラウザのツールを利用して, CSS の要素を調べる.

  • Chrome ならばディベロッパーツール,
  • firefox ならば右クリックから要素を検索

編集画面で該当箇所の css に辿り着いたら, そこを編集する. すると, リアルタイムで変更が確認できる.

class=“gist” class”gist-file” で囲まれている

調べてみると, gist では, <div class=“gist”> などで囲まれていることがわかる.

以下のような StyleSheet に追加する.

/* for gist */
.gist {
    font-size: 16px;
}
.gist-file div{
    background-color: black!important;
}

.gist-file .pl-vo{
    color: white!important;
}

.gist-file .highlight{
    color: white!important;
}

BookMarks

23 Nov 2014, 13:14

データ抽象と抽象データ型 (ADT) について調べたまとめ (Java)

はじめに

仕事の開発プロジェクトのメンバ (正確にはメンバではなくてアドバイザー) でこわーい人がいて,毎日のようにおびやかされてビクビクしている.

その人が書いたクラス図の意味がわからなかったから質問しにいったときのお話.

やりとり

<div class="outline-text-3" id="text-unnumbered-2">
  <p>
    (hoge さん) 「このクラスがなにを現しているか, そもそもわかってる?? 」
  </p>

  <p>
    (Me) (わかっていないから質問をしにいった)
  </p>

  <p>
    (Me) 「データとそれを扱うための便利な操作をまとめたクラスですか? 」
  </p>

  <p>
    (hoge さん) 「それって, ただオブジェクト指向の一般論を言っているだけでは? 」
  </p>

  <p>
    (Me) (にが笑い&#x2026;)
  </p>

  <p>
    (hoge さん) 「わかってないのに, わかったふりをしているよね? 」
  </p>

  <p>
    (hoge さん) 「便利な操作ってなに? そんなことだから, いつも考え方が手続的なんだ!! 」
  </p>

  <p>
    そんなこんなで, 今回もひどい目にあい, あたくしは週末に心療内科にいって坑うつ剤を増量してもらうはめになった.
  </p>
</div>

Answer

<div class="outline-text-3" id="text-unnumbered-3">
  <p>
    その人のいうことには,
  </p>

  <p>
    「このクラスは, アプリケーションのためのデータ型. アプリケーションのベースになるもの. Integer 型や String 型と同じようなもの. 」
  </p>

  <p>
    「アプリケーションを設計するということは, まずそのアプリケーションで利用される データ型を定義するということからはじめる.」
  </p>

  <p>
    「その後, 自分が定義したデータ型を操作するインタプリタを設計する. Java をつかっているものの, Java はそれらのデータ型のインタプリタでしかない」
  </p>

  <p>
    だそうだ.というわけで, 今回は抽象データ型について調べてみた.
  </p>

  <p>
    情報元は, Wikipedia だったり, CPMCP 本だったり.
  </p>
</div>

データ型とは

互いに関係する値の集合.

大きく, 2 種類に分けられる.

基本型は, よく知っているので, 今回は抽象データ型に注目.

抽象データ型とは

  • 自身で定義した型.
  • 状態を持たない.
  • Abstract Data Type (ADT) という.
  • 値の集合とそれらに関係する操作の集合, それぞれ別々に保持しているもの. (別々というところが Object の違い)

ラッパー

<div class="outline-text-4" id="text-unnumbered-6">
  <p>
    値の集合に直接アクセスさせないための操作.(CPMCP p210)
  </p>

  <ul class="org-ul">
    <li>
      値を安全に保持するためには, 鍵 (key) を利用して (包む) 操作を追加する.
    </li>
  </ul>

  <p>
    [sourcecode language=&#8221;bash&#8221; title=&#8221;&#8221;]<br /> Key={NewName}<br /> SS={Chunk.new w (Key:S)}<br /> [/sourcecode]
  </p>

  <p>
    包み, ほどきを行うデータ抽象をラッパーと定義する.
  </p>

  <p>
    [sourcecode language=&#8221;bash&#8221; title=&#8221;&#8221;]<br /> proc {NewWrapper ?Wrap ?Unwrap}<br /> Key={NewName} in<br /> fun {Wrap X}<br /> {Chunk.new w{Key:X}}<br /> end<br /> fun {Unwrap X}<br /> try W.Key catch _ then raise error (unwrap (W)) end end<br /> end<br /> end<br /> [/sourcecode]
  </p>

  <p>
    以下のように, Wrap, Unwrap する.
  </p>

  <p>
    [sourcecode language=&#8221;bash&#8221; title=&#8221;&#8221;]<br /> S={a b c}<br /> SS={Wrap S}<br /> S={Unwrap SS}<br /> [/sourcecode]
  </p>
</div>

データ抽象 (Data Abstraction)

データを抽象的に使う, 使い方.実装にとらわれずにデータを使うこと. インタフェースと呼ばれる規則にしたがって使用される具体化の集合.

データ抽象を型 (Type) といって済ますこともある. 抽象データ型 (ADT) は, 特殊なデータ抽象. 値の集合と, それに関する操作の集合.(CPMCP p431)

Data Abstruction は 操作が値にバインディングされているかいなかで, 2 つの種類に分けられる.

  • Abstruct Data Type (ADT) 値と操作をベツベツに保持する
  • Object 値と操作を一緒に保持する.

オブジェクト

<div class="outline-text-3" id="text-unnumbered-8">
  <p>
    値と操作をひとつのまとまりとしたもの.
  </p>

  <p>
    現在オブジェクト指向言語と呼ばれているものは,実際には,
  </p>

  <ul class="org-ul">
    <li>
      Abstruct Data Type (Java Integer 型)
    </li>
    <li>
      オブジェクト (Java Object 型)
    </li>
  </ul>

  <p>
    の 2 つを合わせもっている.
  </p>

  <p>
    その意味で, オブジェクト指向言語と言うよりは, 抽象データ言語というほうが正しい.
  </p>
</div>

クラス

<div class="outline-text-3" id="text-unnumbered-9">
  <p>
    抽象データからなるデータ構造.
  </p>

  <p>
    属性とメソッドはレコードデータ構造によって管理されているだけ.
  </p>

  <p>
    Class とは, Pair ( attrs[属性の集合] : methods[メソッドの集合]) )
  </p>

  <p>
    Class の 生成 (new) メソッドで オブジェクトが生成される.(インスタンス化)
  </p>

  <p>
    Class という概念によって, オブジェクトの&#8221;宣言&#8221;と&#8221;生成 (new)&#8221;を分離する.
  </p>
</div>

実例

オブジェクト指向における, メソッドの動的ディスパッチを自力で実装. なんてめんどいんだ.

本来ならば, Operation クラスで保持するものは, String ではなくてクロージャだけど, Java7 では実現できない.

hoge さんから提示されたクラス図も, 大体はこんな感じで, HashMap に値やらメソッドやらを保持していた.

[sourcecode language=”java” title=””]
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class ADTSample {
public static void main (String[] args) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException,
NoSuchMethodException, SecurityException {
ObjectSample obj = new ObjectSample ();
System.out.println (obj.getAttr1 () + " " + obj.getAttr2 ());

ObjectSample2 obj2 = new ObjectSample2 ();
System.out.println (obj2.call (Key.NUM) + " " + obj2.call (Key.STRING));
}
}

class ObjectSample {
int attr1 = 3;
String attr2 = "hello";

public int getAttr1 () {
return attr1;
}

public String getAttr2 () {
return attr2;
}

public void setAttr2 (String attr2) {
this.attr2 = attr2;
}
}

enum Type {
INT,
STRING
}

enum Key {
NUM,
STRING
}

class ObjectSample2 {
private Map attrs = new HashMap();
private Map methods = new HashMap();

public ObjectSample2 () {
// Attributes
attrs.put (Key.NUM, new Attribute (3, Type.INT));
attrs.put (Key.STRING, new Attribute ("hello", Type.STRING));

// Operations
methods.put (Key.NUM, new Operation ("getAttr1"));
methods.put (Key.STRING, new Operation ("getAttr2"));
}

public Object call (Key key) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException,
NoSuchMethodException, SecurityException {

Operation ope = methods.get (key);
Method method = this.getClass ().getMethod (ope.method, Key.class);
return method.invoke (this, key);
}

public Object getAttr1 (Key key) {
Attribute attr = attrs.get (key);
return attr.value;
}

public Object getAttr2 (Key key) {
Attribute attr = attrs.get (key);
return attr.value;
}
}

class Attribute {
Object value;
Type type;

public Attribute (Object value, Type type) {
this.value = value;
this.type = type;
}
}

class Operation {
String method;

public Operation (String method) {
this.method = method;
}
}
[/sourcecode]

23 Nov 2014, 06:35

Windows での コマンドラインからコピーするコマンドまとめ (xcopy, robocopy, copy)

はじめに

コマンドプロンプトからフォルダのコピーがしたかったので, 調べてみた.

Windows 標準コピーコマンド

Windows8 には, 標準で以下のコマンドが利用できる.

  • copy
  • xcopy
  • robocopy

copy

<div class="outline-text-3" id="text-2-1">
  <p>
    Windows 標準のファイルコピーコマンド.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://www.k-tanaka.net/cmd/copy.php">コマンドプロンプト copy &#8211; ファイルをコピーする</a>
    </li>
  </ul>
</div>

xcopy

<div class="outline-text-3" id="text-2-2">
  <p>
    copy の改良版. copy よりも高機能.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://www.k-tanaka.net/cmd/xcopy.php">コマンドプロンプト xcopy &#8211; ファイルをディレクトリ構造ごとコピーする</a>
    </li>
  </ul>

  <p>
    ディレクトリツリーごとコピーできるところが, copy との最大の違い. xcopy があれば, copy はいらない.
  </p>

  <p>
    copy は内部コマンド, xcopy は外部コマンド.
  </p>

  <p>
    [sourcecode language=&#8221;bash&#8221; title=&#8221;&#8221;]<br /> xcopy /e "C:\Users\tsu-nera\Desktop\test" "\\192.168.100.100\共有"<br /> [/sourcecode]
  </p>
</div>

robocopy

<div class="outline-text-3" id="text-2-3">
  <p>
    xcopy よりも高機能なコマンド. リモート間のフォルダ同期ができる. バックアップならば, robocpy が適している.
  </p>

  <ul class="org-ul">
    <li>
      <a href="http://www.atmarkit.co.jp/ait/articles/0704/20/news130.html">Windows TIPS:robocopy でフォルダをバックアップ/ 同期させる &#8211; @ IT</a>
    </li>
  </ul>
</div>

速度について

xcopy と robocopy

<div class="outline-text-3" id="text-3-1">
  <p>
    比較動画をみつけた. robocopy の勝利.
  </p>

  <p>
    <iframe width="420" height="315" src="//www.youtube.com/embed/1y7vmIvK2z8" frameborder="0" allowfullscreen></iframe> </div> </div> 

    <div id="outline-container-sec-3-2" class="outline-3">
      <h3 id="sec-3-2">
        Explore での手動コピーとの違い
      </h3>

      <div class="outline-text-3" id="text-3-2">
        <p>
          調べてみると, xcopy のほうが手動コピーよりも早いらしい.
        </p>

        <ul class="org-ul">
          <li>
            <a href="http://okwave.jp/qa/q6547486.html">通常コピーと CMD でコピー速度の差の理由は? 【 OKWave 】</a>
          </li>
        </ul>

        <p>
          ちなみに, explore.exe にもコマンドラインオブションはある. コマンドプロンプトから指定したフォルダを開くことがてきる. コピーや移動はできないみたい.
        </p>

        <ul class="org-ul">
          <li>
            <a href="http://support.microsoft.com/kb/152457/ja">Windows エクスプローラのコマンドライン オプション</a>
          </li>
        </ul>
      </div>
    </div>

    <div id="outline-container-sec-3-3" class="outline-3">
      <h3 id="sec-3-3">
        FastCopy
      </h3>

      <div class="outline-text-3" id="text-3-3">
        <p>
          ためしていないけれども, FastCopy というものがあるらしい. なんでも, robocopy, xcopy よりも高速とか.
        </p>

        <ul class="org-ul">
          <li>
            <a href="http://www.se-support.com/server/fileserver-copy.html">高速コピーツール「 FastCopy 」はホントに早かった! ファイルサーバー移行テスト</a>
          </li>
        </ul>
      </div>
    </div></div> 

    <div id="outline-container-sec-4" class="outline-2">
      <h2 id="sec-4">
        おまけ
      </h2>

      <div class="outline-text-2" id="text-4">
        <p>
          ダミー用データ作成.以下を参考に .
        </p>

        <ul class="org-ul">
          <li>
            <a href="http://www.atmarkit.co.jp/ait/articles/0209/28/news002.html">Windows TIPS:巨大なサイズのファイルを簡単に作る方法 &#8211; @ IT</a>
          </li>
        </ul>

        <p>
          [sourcecode language=&#8221;bash&#8221; title=&#8221;&#8221;]<br /> # 1KB のファイル作成.<br /> fsutil file createnew 1K_test 1024
        </p>

        <p>
          # 1MB のファイル作成.<br /> fsutil file createnew 1M_test 1048576
        </p>

        <p>
          # 1GB のファイル作成.<br /> fsutil file createnew 1G_test 1073741824<br /> [/sourcecode]
        </p>
      </div>
    </div>

19 Nov 2014, 15:15

Java で TreeSet と Comparator を実装した

はじめに

Java で, 順序づけをした集合をイテレーティブに処理したい.

ちなみに, PriorityQueue では, 実現できなかった…

TreeSet

SortedSet, TreeSet を利用する.

SortedSet はインタフェース, TreeSet は クラスという違いがある.

Comparator

順序をつけるために java.util.Comparator インタフェースを利用する. これは,コレクションの順序づけをおこなうための比較関数,compare をもつ.

以下の記事が詳しい.

具体例

優先度をもつ以下のようなオブジェクトを TreeSet に格納することを考える.

class MyClass {
    private char a;
    private int priority;

    public MyClass (char a, int priority) {
        this.a = a;
        this.priority = priority;
    }

    public int getPriority () {
        return priority;
    }

    public String toString () {
        return "char: " + a + " priority: " + priority;
    }
}

まずは, Comparator を作成する.

import java.util.Comparator;

class MyComparator implements Comparator {
    @Override
    public int compare (Object arg0, Object arg1) {
        MyClass x = (MyClass) arg0;
        MyClass y = (MyClass) arg1;

        int xp = x.getPriority ();
        int yp = y.getPriority ();      

        if (xp < yp) {
            return 1;
        } else if (xp > yp) {
            return -1;
        } else{
            return 0;
        }
    }
}

最後に TreeSet の実装.

import java.util.TreeSet;

public class SortedSetSample {
    public static void main (String[] args) {
        MyClass A = new MyClass ('a', 3);       
        MyClass B = new MyClass ('b', 1);
        MyClass C = new MyClass ('c', 2);

        TreeSet<MyClass> set = new TreeSet<MyClass>(new MyComparator ());

        set.add (A);
        set.add (B);
        set.add (C);

        for (MyClass obj: set) {
            System.out.println (obj);
        }
    }
}

実行結果

char: a priority: 3
char: c priority: 2
char: b priority: 1

Full Code

import java.util.Comparator;
import java.util.TreeSet;

public class SortedSetSample {
    public static void main (String[] args) {
        MyClass A = new MyClass ('a', 3);       
        MyClass B = new MyClass ('b', 1);
        MyClass C = new MyClass ('c', 2);

        TreeSet<MyClass> set = new TreeSet<MyClass>(new MyComparator ());

        set.add (A);
        set.add (B);
        set.add (C);

        for (MyClass obj: set) {
            System.out.println (obj);
        }
    }
}

class MyComparator implements Comparator {
    @Override
    public int compare (Object arg0, Object arg1) {
        MyClass x = (MyClass) arg0;
        MyClass y = (MyClass) arg1;

        int xp = x.getPriority ();
        int yp = y.getPriority ();      

        if (xp < yp) {
            return 1;
        } else if (xp > yp) {
            return -1;
        } else{
            return 0;
        }
    }
}

class MyClass {
    private char a;
    private int priority;

    public MyClass (char a, int priority) {
        this.a = a;
        this.priority = priority;
    }

    public int getPriority () {
        return priority;
    }

    public String toString () {
        return "char: " + a + " priority: " + priority;
    }
}

Special Thanks

19 Nov 2014, 13:53

Java での優先順位付きキューの使い方まとめ (PriorityQueue)

はじめに

優先順位付きキューのを PriorityQueue という. キューの中で最大 (最小) のものを抜き出す場合などに利用する.

1 年前は C++ で書いた

思いかえせば一年前, C++ で PriorityQueue の記事を書いた.

また, 1 年前の coursera の講義で, 自前で PriorityQueue の実装をした.

参考にした java コード:

使い方

Java では, 以下のライブラリを利用する.

宣言

優先順位は,いかの 2 つ指定方法がある.

  • 自然順位づけ
  • 自分で順位をつける

デフォルトでは小さい順で 取り出される.

import java.util.PriorityQueue;

関数

要素を追加する

pq.add (1);

先頭の要素を取り出す

最大 (または最小) の先頭を取り出します.

pq.poll ();

要素を調べる

// キューがからかどうかを調べる
pq.isEmpty ();

// 要素数をしらべる
pq.size ();

Sample

import java.util.PriorityQueue;

public class PriorityQueueSample {
    public static void main (String[] args) {

        // 宣言
        PriorityQueue pq = new PriorityQueue ();

        // 挿入
        pq.add (2);             
        pq.add (3);     
        pq.add (1);

        // 先頭の要素を取り出す
        System.out.println (pq.poll ());

        // キューがからかどうかを調べる
        System.out.println (pq.isEmpty ());     

        // 要素数をしらべる
        System.out.println (pq.size ());                                                     
    }
}

独自定義の順位づけ

Comparator を実装し, PriorityQueue 生成時に引数で渡す.

import java.util.PriorityQueue;
import java.util.Comparator;

public class PriorityQueueSample {
    public static void main (String[] args) {

        // 宣言
        PriorityQueue pq = new PriorityQueue (3, new MyComparator ());

        // 挿入
        pq.add (2);             
        pq.add (3);     
        pq.add (1);

        // 先頭の要素を取り出す
        System.out.println (pq.poll ());
        System.out.println (pq.poll ());
        System.out.println (pq.poll ());        
    }
}

class MyComparator implements Comparator {
    @Override
    public int compare (Object arg0, Object arg1) {
        int x = (int) arg0;
        int y = (int) arg1;

        if (x < y) {
            return 1;
        } else if (x > y) {
            return -1;
        } else{
            return 0;
        }
    }
}

Iterator の注意

これだと, 1, 3, 2 という順番で出力される.

PriorityQueue は, 取り出すときに優先順位ごとにとりだされるので, Iterator でまわしても, 順番どおりにならない.

import java.util.PriorityQueue;

public class PriorityQueueSample {
    public static void main (String[] args) {

        PriorityQueue pq = new PriorityQueue ();

        pq.add (2);             
        pq.add (3);     
        pq.add (1);

        for (Object i: pq) {
            System.out.println (i);
        }
    }
}

Special Thanks

18 Nov 2014, 13:45

Java のリフレクションでインスタンスやメソッドを動的生成する

リフレクションとは

リフレクションとは, プログラム実行中に, クラス名やメソッド名を動的に指定することができる技術.

以下, Wikipedia のソースをそのまま引用します.

// リフレクションなし
Foo foo = new Foo ();
foo.hello ();

// リフレクション
Class cl = Class.forName ("Foo");
Method method = cl.getMethod ("hello");
method.invoke (cl.newInstance ());

リフレクションのデメリット

リフレクションはカプセル化を壊す?

リフレクションを利用すると, クラス内部のメソッドやフィールドをみたり, フィールドを書き換えたりできるという, ハッカー的な機能.

こういうオブジェクト指向に反する機能は, ユーティリティクラスのメソッド呼び出しに効果的である.

リフレクションは遅い??

リフレクションは遅いということがいわれている.以下のサイトが参考になる.

  • リフレクションでのオブジェクトの作成はオーバーヘッドがほとんどない
  • メンバーフィールドにアクセスするのは遅すぎるのでやらないほうがいい.
  • メソッド呼び出しは 5 から 20 倍遅いので, 使う場合は注意する

コンパイル時の型チェックができない

リフレクションはプログラム実行時にメソッド呼び出し方法が決まるので, コンパイル時の事前型チェックができない.

リフレクションよりもインタフェースを選ぶ

Effective Java p233 にのっている助言.

Java でのリフレクション

java.lang.reflect というパッケージがある.

リフレクションでインスタンス生成

  • Class.forName (“クラス名”) で クラス生成
  • newInstance () で インスタンス生成
Class clazz = Class.forName ("Foo");
Foo foo = (Foo) clazz.newInstance ();

リフレクションでメソッド呼び出し

  • getMethod (“メソッド名”) でメソッド定義
  • invoke (object) でメソッド呼び出し
Foo foo2 = new Foo ();
Method method = foo2.getClass ().getMethod ("bar");
method.invoke (foo2);

Code

import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;

public class ReflectionSample {  
    public static void main (String []args) {  
        try {  
            Class clazz = Class.forName ("Foo");
            Foo foo = (Foo) clazz.newInstance ();
            foo.bar ();
        } catch (ClassNotFoundException e) {
            // クラスが存在しない
            e.printStackTrace ();  
        } catch (InstantiationException e) {
            // インスタンス作成不可
            e.printStackTrace ();  
        } catch (IllegalAccessException e) {
            // 呼び出し:アクセス違反, 保護されている         
            e.printStackTrace ();  
        }

        Foo foo2 = new Foo ();
        try {
            // 引数なし
            Method method = foo2.getClass ().getMethod ("bar");
            method.invoke (foo2);

            // 引数あり
            Method method2 = foo2.getClass ().getMethod ("pee", int.class);
            method2.invoke (foo2, 1);
        } catch (NoSuchMethodException e) {
            // メソッドが存在しない
            e.printStackTrace ();
        } catch (IllegalArgumentException e) {
            // 呼び出し:引数が異なる
            e.printStackTrace ();
        } catch (IllegalAccessException e) {
            // 呼び出し:アクセス違反, 保護されている
            e.printStackTrace ();
        } catch (InvocationTargetException e) {
            // ターゲットとなるメソッド自身の例外処理
            e.printStackTrace ();
        }
    }
}

class Foo {
    public Foo () {
        System.out.println ("Constructor is called");
    }

    public void bar () {
        System.out.println ("method is called");
    }

    public void pee (int i) {
        System.out.println (i);
    }
}

Special Thanks

17 Nov 2014, 14:46

Java でスレッドプールを実装してみた

はじめに

仕事でスレッドプールを利用する機会があるので, Java でスレッドプールをつかう方法を調べてみた.

Java には, JDK1.5 から ExecutorService という便利なライブラリがあるようだ.

スレッドプールとは

はじめに, スレッドプールについての一般的な説明.

スレッドプールとは, 複数のスレッドをあらかじめ作成して待機させておき, タスクが来たら待っているスレッドにタスクを割り当てて 処理を開始させる仕組み.

スレッドの作成と破棄は, それなりにオーバーヘッドがある. そこで, スレッドは暇な時に作成しておいて, 必要になったときにスレッドに処理を割り当てることで, コンテキストスイッチ程度の軽いオーバヘッドで済ますことができる.

また, システム内のメモリは有限なので, 無限にスレッドを作成することはできない. 一度に利用できるスレッド数を制限することで, システムのリソースを制限することができるようになる.

Java でのスレッドプール実装

Executors

Executors クラスは, ExecutorService 生成のための static ファクトリーメソッドをもつ ユーティリティクラス.

主に, 以下のメソッドを用いる.


newFixedThreadPool 指定数スレッドを確保 newSingleThreadExecutor 単一スレッドを確保 newSingleThreadScheduledExecutor 指定期間おきに実行するスレッド (単一スレッド) newScheduledThreadPool 指定時間おきに実行するスレッド


ExecutorService

ExecutorService キューをもつ,スレッドプール.

主に, 以下のメソッドを用いる.


execute タスクを送信する. submit タスクの計算結果や状態を取得するための, Future オブジェクトを返す. shutdown シャットダウンを実行. 以前に送信したタスクは実行, 新規タスクは拒否


ちなみに, Executor というものもある.

ExecutorService は Executor を継承している. Executor は execute メソッドしかもたない.

Execotor にコマンドパターンを実装したものが ExecutorService.

ちなみに

ちなみに, coursera の POSA でスレッドプールの Assignment がある.

Code

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.lang.Thread;

class SampleThreadPool {

  private static class Action implements Runnable {
    @Override
    public void run () {
      System.out.println ("Hello!!");
            try { Thread.sleep (1000);  } catch (InterruptedException e){}
    }
  }

  public static void main (String[] args) {
        // Create Single Thread Pool
    ExecutorService executor = Executors.newSingleThreadExecutor ();

        // Execute Tasks
    executor.execute (new Action ());
    executor.execute (new Action ());

        // End
    executor.shutdown ();
  }
}   

追記: 割り込み例外をあげる (2015/03/05)

割り込み例外をあげるには, 以下のような手順を踏む.

  1. execute () メソッドの代わりに submit () をコール
  2. future オブジェクトを取得
  3. future.cancel (true)
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.HashMap;
import java.lang.Thread;

class ThreadInteraptSample {

    private static class Action implements Runnable {
        public int id;

        public Action (int id) {
            this.id = id;
        }

        @Override
        public void run () {
            System.out.println ("id=" + id + " start!!");
            try {
                Thread.sleep (2000);
                System.out.println ("Time out!!");
            } catch (InterruptedException e){
                System.out.println ("Interrupted id=" + id);
            }
        }
    }

    // http://java.keicode.com/lang/multithreading-cancel.php
    public static void main (String[] args) {
        Future future1, future2, future3;

        // Create Single Thread Pool
        ExecutorService executor = Executors.newSingleThreadExecutor ();

        // Execute Tasks
        Action act1 = new Action (1);
        Action act2 = new Action (2);
        Action act3 = new Action (3);

        HashMap<Action, Future> map = new HashMap<Action, Future>();
        map.put (act1, future1 = executor.submit (act1));
        map.put (act2, future2 = executor.submit (act2));
        map.put (act3, future3 = executor.submit (act3));

        try {Thread.sleep (3000);} catch (Exception e) {}

        for (Action action: map.keySet ()) {
            if (action.id == 2) {
                map.get (action).cancel (true);
                break;
            }
        }

        executor.shutdown ();
    }
}

Bookmarks

17 Nov 2014, 14:25

Java のユーティリティクラスはシングルトンパターン/ フライウェイトパターンで実装する

はじめに

今日から仕事ではじめて Java の開発をはじめることになったので, とてもうれしい.

Java の常識あるあるのなかに, ユーティリティクラスというものがある. みんな当たり前のように話しているけれども, 自分は知らないので調べた.

ユーティリティクラスとは

以下の特徴をもつ.

  • いろんなところで繰り返し利用される処理をまとめたクラス.
  • インスタンス化されない.
  • すべてのメソッドは static で宣言される.
  • 状態を持たない処理をユーティリティにすることが多い.

C 言語 とかでよくライブラリと呼ばれているのを見かけたことがある. オブジェクト指向っぽくない. そんなことを考えたら, 同じような意見をちらほら発見した.

実現方法

メソッドには static をつける

static をつけることで, クラスをインスタンスすることなく メソッドを利用できる.

class SampleSingleton {
    static class SampleUtil {
        private SampleUtil () {} // インスタンス化を禁止するテクニック
        public static int plus (int x, int y) { return x + y; }
        public static int minus (int x, int y) { return x - y; }        
    }
    public static void main (String[] args) {
        System.out.println (SampleUtil.plus (1,1));
        System.out.println (SampleUtil.minus (2,1));        
    }
}

状態をもつ場合は, シングルトンパターンを適用する

なにかの値を保持する場合は, デザインパターンであるシングルトンパターンを利用する.

一般的なシングルトンパターンの実装方法は以下.

  • private な 定数に オブジェクトを保存
  • オブジェクトは getInstance () メソッドで取得

フライウェイトパターンで改良する

シングルトンパターンは フライウェイトパターンと合わせて利用されることがおおい.

特徴は,

  • private な 変数に オブジェクトを保存.
  • オブジェクトが存在すれば, getInstance で渡す. オブジェクトが存在しなければ, オブジェクトを作成して getInstance で渡す.

実装例

class SampleSingleton {
    static class SingletonUtil {
        private static final SingletonUtil INSTANCE = new SingletonUtil ();

        public static SingletonUtil getInstance (){ return INSTANCE; }
        public static int plus (int x, int y) { return x + y; }
        public static int minus (int x, int y) { return x - y; }        
    }


    public static void main (String[] args) {
        System.out.println (SingletonUtil.getInstance ().plus (1,1));
        System.out.println (SingletonUtil.getInstance ().minus (2,1));      
    }
}

または, Enum を利用するとという手もある. Effective Java の本では, この方法を推奨している.

class SampleSingleton {
    static public enum EnumUtil {
        INSTANCE;

        public static int plus (int x, int y) { return x + y; }
        public static int minus (int x, int y) { return x - y; }        
    }

    public static void main (String[] args) {
        System.out.println (EnumUtil.INSTANCE.plus (1,1));
        System.out.println (EnumUtil.INSTANCE.minus (2,1));     
    }
}

Special Thanks

16 Nov 2014, 14:31

エレガントな Effective Java の Builder Pattern を実装してみた

はじめに

Effective Java を読んでいたら, エレガントなコードを見つけたので思わずメモ.

引数がおおいオブジェクトを生成するとき….

王道は 2 つの方法がある.

テレスコーピング・コンストラクタパターン

  • コンストラクタの引数に情報を追加する方法.
  • 引数が増えるたびに, 異なる型のコンストラクタの作成が必要.
///////////////////////////////////////////
// テレスコーピング・コンストラクタパターン
///////////////////////////////////////////
public Hoge (int a, int b, int c, int d) {
    this.a = a;
    this.b = b;
    this.c = c;
    this.d = d;
}

JavaBeans パターン

  • コンストラクタには, 引数を与えない.
  • 代わりに, setter を用意する.
/////////////////////
// Javabeans パターン
/////////////////////
public Hoge () {
    this.a = 0;
    this.b = 0;
    this.c = 0;
    this.d = 0;
}
public static void setA (int x) { a = x; }
public static void setB (int x) { b = x; }
public static void setC (int x) { c = x; }
public static void setD (int x) { d = x; }

エレガントな Builder パターン

最後に, エレガントな Builder パターン.

  • コンストラクタの引数には, Builder オブジェクトを渡す.
  • Builder オブジェクトの引数には必須の情報を渡す.
  • 任意の引数には, setter を用意する.

    エレガントな行はこれ.

Hoge hoge = new Builder (1,2).c (3).d (4).build ();

完全版のコードは以下.

class BuilderSample {

    public static class Hoge {
        private static int a, b; // should be set
        private static int c, d; // optional

        /////////////////////
        // Builder パターン
        /////////////////////
        private Hoge (Builder builder) {
            a = builder.a;
            b = builder.b;
            c = builder.c;
            d = builder.d;          
        }
    }

    public static class Builder {
        private static int a, b; // should be set
        private static int c, d; // optional

        public Builder (int a, int b) {
            this.a = a;
            this.b = b;
            this.c = 0;
            this.d = 0;
        }

        public Builder c (int x) { c = x; return this; }
        public Builder d (int x) { d = x; return this; }
        public Hoge build () { return new Hoge (this); }
    }

    public static void main (String[] args) {
        Hoge hoge = new Builder (1,2).c (3).d (4).build ();
    }

}

Gof とは違う??

最後に, Gof の Builder パターンとはすこし意味合いがことなるように, Effective Java ではつかわれているようだ.