--/--/--

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

2008/02/16

ポインタ入門 for Java プログラマ

c のポインタを理解できない Java プログラマへ

俺もその中の一人だった。ポインタの仕組みは分かるんだけど、 c のポインタが理解できないというか。演算子がごちゃごちゃしてて分かりにくい。

そこで Java でポインタの真似をすることでこれを打開してみようと思いついた。 ポインタの仕組みさえ分かっておけば、基本的なところは簡単に真似できる。

ではまず、簡単な c のサンプルを見てみる。

 #include <stdio.h>

void proc(int a) {
    a += 10;
}

void procp(int *ap) {
    *ap += 10;
}

int main() {

    int a = 1;
    int *ap = &a;

    printf("a before : %d\n", a);
    proc(a);
    printf("a after  : %d\n", a);

    printf("-----------\n");

    printf("ap before: %d\n", *ap);
    procp(ap);
    printf("ap after : %d\n", *ap);
}

値渡しと参照渡しの違いを見せるサンプルである。ちなみにこのサンプルでは 引数をそのままいじっているが、これはよろしくない。真似するべからず。

では、Java でこれを真似してみる。

実は Java はプリミティブ型以外、全てポインタである。つまりぜーんぶ参照で、関数に受け渡したりなんなりするのも、プリミティブ型以外は全部参照渡しなのだ。これを利用すればいい。 もっとも、プリミティブ型のポインタだけを考慮するなら Integer とかのラッパークラスを 使えばいいが、もうちょっとユニバーサルな Pointer クラスを作る。

 public class Pointer<V> {

    public V value;

    public Pointer(V initial) {
        value = initial;
    }

}

指定された型の値を保持するだけのクラスである。

次に、C のサンプルを真似る Java のサンプルを作る。

 public class PointerSample {

    public static void main(String[] args) {
        int a = 1;
        Pointer<Integer> ap = new Pointer<Integer>(a);

        System.out.printf("a before : %d%n", a);
        proc(a);
        System.out.printf("a after  : %d%n", a);

        System.out.println("---------");

        System.out.printf("ap before: %d%n", ap.value);
        proc(ap);
        System.out.printf("ap after : %d%n", ap.value);
    }

    static void proc(int a) {
        a += 10;
    }

    static void proc(Pointer<Integer> ap) {
        ap.value += 10;
    }

}

結果は同じになる。a のほうは値が変わらず、ap のほうは値が変わる。 どちらの ap も内部の値が変わっているだけで、参照自体は変わって いないということに注意すれば、ポインタってなんなのさってことは分かるかと。

ただし次のようにはならないので、やはり厳密には真似できていない。

// さっきの c コードの続き
printf("a after  :%d\n", a); // 11 になる

これは ap が a のアドレスを直接指しているということを表す。 一方 Java の Pointer はそうではない。Pointer が new されてるから、そもそも元の a とは違うアドレスになってるということ。だから Java ではこの c コードのようなことにはならない。

真似しようとするなら、次のような感じ?当然実現できない。

int a = 1;
Pointer<Integer> ap = a.getAddress();

Pointer を a の参照として new Pointerするのではなく、a のアドレスを直接受け取る。

ポインタのポインタも c の構文のせいでややこしくなってるだけで、 Java で見れば一発で分かる。

Object o = new Object();
Pointer<Object> op = new Pointer<Object>(o);
Pointer<Pointer<Object>> opp = new Pointer<Pointer<Object>>(op);

以上の通り、ポインタってのは実は全然難しくない。難しいと感じるのは c の 構文のせいでしょう。要は参照なのだよ参照。

ちなみに、ここで作った Pointer クラスの似たようなものとして、java.lang.ref.Reference ってクラスが Java の標準APIにある。使ったことないけど。いらんメソッドがあっていやだったから、Pointer クラスを作ってみた。

スポンサーサイト

comment

post




上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。