web-dev-qa-db-ja.com

Javaでポインターを使用するにはどうすればよいですか?

Javaにはポインターがないことは知っていますが、Javaプログラムはポインターを使用して作成でき、これはJavaの専門家である少数の人が行うことができると聞きました。本当ですか?

97
user213038

Java内のすべてのオブジェクトは参照であり、ポインターのように使用できます。

abstract class Animal
{...
}

class Lion extends Animal
{...
}

class Tiger extends Animal
{   
public Tiger() {...}
public void growl(){...}
}

Tiger first = null;
Tiger second = new Tiger();
Tiger third;

Nullの逆参照:

first.growl();  // ERROR, first is null.    
third.growl(); // ERROR, third has not been initialized.

エイリアシングの問題:

third = new Tiger();
first = third;

失われた細胞:

second = third; // Possible ERROR. The old value of second is lost.    

これを安全にするには、最初に古い値のsecondがもう必要ないことを保証するか、別のポインターにsecondの値を割り当てます。

first = second;
second = third; //OK

Secondに他の方法(NULL、new ...)で値を与えることは潜在的なエラーと同じくらい多く、それが指すオブジェクトを失う可能性があることに注意してください。

Javaシステムは、newを呼び出し、アロケーターが要求されたセルを割り当てることができない場合、例外(OutOfMemoryError)をスローします。これは非常にまれであり、通常は暴走再帰に起因します。

言語の観点から、ガベージコレクタへのオブジェクトの放棄はエラーではないことに注意してください。プログラマーが知っておく必要があるものです。同じ変数が異なる時間に異なるオブジェクトを指すことができ、それらを参照するポインターがない場合、古い値は再利用されます。ただし、プログラムのロジックでオブジェクトへの参照を少なくとも1つ保持する必要がある場合、エラーが発生します。

初心者は次のエラーをよくします。

Tiger tony = new Tiger();
tony = third; // Error, the new object allocated above is reclaimed. 

おそらくあなたが言ったことは:

Tiger tony = null;
tony = third; // OK.

不適切なキャスティング:

Lion leo = new Lion();
Tiger tony = (Tiger)leo; // Always illegal and caught by compiler. 

Animal whatever = new Lion(); // Legal.
Tiger tony = (Tiger)whatever; // Illegal, just as in previous example.
Lion leo = (Lion)whatever; // Legal, object whatever really is a Lion.

Cのポインター:

void main() {   
    int*    x;  // Allocate the pointers x and y
    int*    y;  // (but not the pointees)

    x = malloc(sizeof(int));    // Allocate an int pointee,
                                // and set x to point to it

    *x = 42;    // Dereference x to store 42 in its pointee

    *y = 13;    // CRASH -- y does not have a pointee yet

    y = x;      // Pointer assignment sets y to point to x's pointee

    *y = 13;    // Dereference y to store 13 in its (shared) pointee
}

Javaのポインター:

class IntObj {
    public int value;
}

public class Binky() {
    public static void main(String[] args) {
        IntObj  x;  // Allocate the pointers x and y
        IntObj  y;  // (but not the IntObj pointees)

        x = new IntObj();   // Allocate an IntObj pointee
                            // and set x to point to it

        x.value = 42;   // Dereference x to store 42 in its pointee

        y.value = 13;   // CRASH -- y does not have a pointee yet

        y = x;  // Pointer assignment sets y to point to x's pointee

        y.value = 13;   // Deference y to store 13 in its (shared) pointee
    }
} 

PDATE:コメントで示唆されているように、Cにはポインター演算があることに注意する必要があります。ただし、Javaにはありません。

232
Sajad Bahmani

Javaにはポインターがあります。 Javaでオブジェクトを作成するときはいつでも、実際にはオブジェクトへのポインターを作成しています。その後、このポインターを別のオブジェクトまたはnullに設定しても、元のオブジェクトは引き続き存在します(ガベージコレクションを保留中)。

Javaでできないことは、ポインター演算です。特定のメモリアドレスを逆参照したり、ポインタをインクリメントしたりすることはできません。

本当に低レベルにしたい場合、それを行う唯一の方法は Java Native Interface ;その場合でも、低レベルの部分はCまたはC++で行う必要があります。

42
Michael Myers

Javaにはポインターデータ型がないため、Javaでポインターを使用することはできません。少数の専門家でさえ、Javaでポインターを使用することはできません。

次の最後の点も参照してください。 Java Language Environment

29
Fortega

JavaにはCのようなポインターはありませんが、変数によって「参照」される新しいオブジェクトをヒープ上に作成できます。ポインタの欠如は、Javaプログラムがメモリ位置を不正に参照するのを防ぐことであり、また、ガベージコレクションがJava仮想マシンによって自動的に実行されることを可能にします。

8
Zubair

Unsafeクラスを使用して、アドレスとポインターを使用できます。しかし、名前が示すように、これらの方法は安全ではなく、一般的に悪い考えです。使用方法を誤ると、JVMがランダムに死ぬ可能性があります(実際には、C/C++でポインターを誤って使用すると同じ問題が発生します)。

ポインタに慣れていて、それが必要だと思うかもしれませんが(他の方法でコーディングする方法がわからないため)、あなたはそうではないことに気付くでしょう。

7
Peter Lawrey

Javaにはポインターがありますが、C++またはCでできるようにそれらを操作することはできません。オブジェクトを渡すとき、そのオブジェクトにポインターを渡しますが、C++と同じ意味ではありません。そのオブジェクトは逆参照できません。ネイティブアクセサを使用して値を設定すると、Javaがポインタを介してそのメモリ位置を認識するため、値が変更されます。しかし、ポインターは不変です。ポインタを新しい場所に設定しようとすると、代わりに、他と同じ名前の新しいローカルオブジェクトになります。元のオブジェクトは変更されません。違いを示す簡単なプログラムを次に示します。

import Java.util.*;
import Java.lang.*;
import Java.io.*;

class Ideone {

    public static void main(String[] args) throws Java.lang.Exception {
        System.out.println("Expected # = 0 1 2 2 1");
        Cat c = new Cat();
        c.setClaws(0);
        System.out.println("Initial value is " + c.getClaws());
        // prints 0 obviously
        clawsAreOne(c);
        System.out.println("Accessor changes value to " + c.getClaws());
        // prints 1 because the value 'referenced' by the 'pointer' is changed using an accessor.
        makeNewCat(c);
        System.out.println("Final value is " + c.getClaws());
        // prints 1 because the pointer is not changed to 'kitten'; that would be a reference pass.
    }

    public static void clawsAreOne(Cat kitty) {
        kitty.setClaws(1);
    }

    public static void makeNewCat(Cat kitty) {
        Cat kitten = new Cat();
        kitten.setClaws(2);
        kitty = kitten;
        System.out.println("Value in makeNewCat scope of kitten " + kitten.getClaws());
        //Prints 2. the value pointed to by 'kitten' is 2
        System.out.println("Value in makeNewcat scope of kitty " + kitty.getClaws());
        //Prints 2. The local copy is being used within the scope of this method.
    }
}

class Cat {

    private int claws;

    public void setClaws(int i) {
        claws = i;
    }

    public int getClaws() {
        return claws;
    }
}

これはIdeone.comで実行できます。

7
kingfrito_5005

Java内のすべてのオブジェクトは、プリミティブを除く参照コピーによって関数に渡されます。

実際には、これは、オブジェクト自体のコピーではなく、元のオブジェクトへのポインターのコピーを送信していることを意味します。

これを理解する例が必要な場合は、コメントを残してください。

3
coolest_head

Javaの参照型は、Javaのポインターへのポインターを持つことができないため、Cポインターと同じではありません。

2
zezba9000

技術的には、すべてのJavaオブジェクトはポインターです。ただし、すべてのプリミティブ型は値です。これらのポインターを手動で制御する方法はありません。 Javaは、内部で参照渡しのみを使用します。

1
Poindexter

そうでもない.

Javaにはポインターがありません。あなたが本当に望んでいるなら、あなたは反射のようなものの周りに構築することによってそれらをエミュレートしようとすることができますが、それはすべての複雑さを持つでしょうbenefitsのないポインターの数。

Javaにはポインターが必要ないため、Javaにはポインターがありません。この質問からどのような答えを期待していましたか?つまり、深いところであなたはそれらを何かに使うことができるか、それとも単なる好奇心でしたか?

1
Andrzej Doyle

ゴッドフリー・ノーラン著「Decompiling Android」という本から

セキュリティでは、Javaではポインターは使用されませんと定められているため、ハッカーはアプリケーションからオペレーティングシステムに侵入できません。ポインターがないということは、他の何か----この場合、JVM ----がメモリの割り当てと解放を処理する必要があることを意味します。メモリリークも過去のものになるはずです。 CやC++で書かれたアプリケーションの中には、プログラマが適切なタイミングで不要なメモリを解放することに注意を払わないため、ふるいのようなメモリリークで悪名高いものがあります。また、ガベージコレクションは、メモリの問題のデバッグに費やす時間を減らして、プログラマの生産性を高める必要があります。

1
Mustafa Güven

他の人が言ったように、短い答えは「いいえ」です。

もちろん、Javaポインターで遊ぶJNIコードを書くこともできます。あなたが何を達成しようとしているのかにもよりますが、多分それはあなたをどこかに連れて行くかもしれませんし、そうしないかもしれません。

配列を作成し、配列のインデックスを操作することで、常にポイントをシミュレートできます。繰り返しますが、あなたが達成しようとしていることに応じて、それは役に立つかもしれませんし、そうでないかもしれません。

0
Jay

リテラルへのポインタも持つことができます。自分で実装する必要があります。専門家にとってはかなり基本的なものです;)。 int/object/long/byteの配列を使用し、ポインターを実装するための基本を習得します。これで、任意のint値をその配列int []へのポインターにできます。ポインターをインクリメントしたり、ポインターをデクリメントしたり、ポインターを乗算したりできます。あなたは確かにポインタ演算を持っています!これが、1000個のint属性クラスを実装し、すべての属性に適用される汎用メソッドを持つ唯一の方法です。 int []の代わりにbyte []配列を使用することもできます

ただし、Javaを使用すると、参照によってリテラル値を渡すことができます。線に沿って何か

//(* telling you it is a pointer) public void myMethod(int* intValue);

0
Mordan