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


112

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


1
とにかくサンの実装では。
マイケルマイヤーズ

1
私はそのポインタアドレスを使用することができます

6
JavaオブジェクトのデフォルトのhashCodeはポインターアドレスではなく、hashCodeの規約を注意深く読み直すと、メモリ内の2つの異なるオブジェクトが同じhashCode値を持つ可能性があることがわかります。
アミールアフガニ

3
64ビットおよび32ビットのJavaでは、32ビットのhashCodeはアドレスではありません。hashCodesが一意であるとは限りません。オブジェクトはスペース間を移動し、メモリが圧縮されるため、オブジェクトの場所をメモリ内で移動できますが、hashCodeは変更されません。
Peter Lawrey、

2
C ++ポインターでできることの90%はJavaの屈折で実行できます。残りの10%は、別のオブジェクト内に参照をパッケージ化することで実現できます(これを行うのが必要だとは思いませんでした)
Richard Tingle

回答:


243

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.    

これを安全にするには、最初に秒の古い値が必要ないことを確認するか、別のポインタに秒の値を割り当てる必要があります。

first = second;
second = third; //OK

他の方法(NULL、new ...)で2番目の値を指定すると、同様に潜在的なエラーが発生し、それが指すオブジェクトが失われる可能性があることに注意してください。

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

言語の観点からは、オブジェクトをガベージコレクターに放棄してもエラーにはなりません。これは、プログラマが知っておく必要があることです。同じ変数が異なる時点で異なるオブジェクトを指す可能性があり、ポインターがそれらを参照していない場合、古い値が再利用されます。ただし、プログラムのロジックでオブジェクトへの参照を少なくとも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
    }
} 

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


16
いい答えですが、1つの重要な違いに対処できませんでした。Cにはポインター演算があります。(幸いなことに)Javaではできません。
R.マルティーニョフェルナンデス

10
私はどんな答え、特に人気のある答えも反対票を投じたくありませんが、Javaにはポインターがなく、ポインターのような参照を使用できません。実際のポインタでのみ実行できる特定のことがあります。たとえば、プロセスデータスペース内の任意のバイトを取得または設定できます。Javaでそれを行うことはできません。ここにいる多くの人々が、ポインターが本当は何であるかを理解していないように見えるのは本当に悪いことです。
危険14

5
残念ながらそうだと思います。javaがポインター演算をサポートしないのはなぜ良いと思いますか?
user3462295

2
@ user3462295人々は一般大衆が使用するのは難しすぎると考えているようで、コンパイラまたはデバイスドライバを書く忍者をコーディングすることによってのみ理解できるからです。
iCodeSometime 2015

4
@Danger回答の1行目「Javaのすべてのオブジェクトは参照であり、ポインタのように使用できます。」これが提供できる最良の答えです。唯一の答えが「いいえ、Javaにはポインターがありません」でした。その答えは役に立たなかっただろう。代わりにこの答えは、代わりに何ができるかを述べています。
csga5000 2015

46

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

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

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


9
Javaには単純で単純なポインターがありません。また、ここでの答えの多くが誤った情報を述べている理由を理解することはできません。これはStackOverlfowの人々です!コンピュータサイエンスでのポインタの定義は次のとおりです(このためにGoogleを使用できます):「コンピュータサイエンスでは、ポインタはプログラミング言語オブジェクトであり、その値は、次を使用してコンピュータメモリの別の場所に格納されている別の値を参照(または「ポイント」)そのアドレス。」Javaでの参照はポインタではありません。Javaはガベージコレクションを実行する必要があり、実際のポインタがあった場合、それは間違いです。
危険

3
@危険ポインタは、メモリアドレスを含むデータの一部です。Javaは人々が忘れている2つのものです。言語とプラットフォームです。.NETが言語であるとは言わないだろうが、プラットフォームにはもちろんポインターがあるので、「Javaにはポインターがない」と言っても誤解を招く可能性があることを覚えておく必要がある。これらのポインターは、Java言語を介してプログラマーがアクセスすることはできませんが、ランタイムには存在します。言語の参照は、ランタイムの実際のポインターの上に存在します。
kingfrito_5005 2015

@ kingfrito_5005あなたは私に同意しているようです。「Javaにはポインターがないため、プログラマーはこれらのポインターにアクセスできません」と言ったと思います。参照は、意味的にポインタとは大きく異なります。
2015

1
@危険これは本当ですが、私はこれらのケースではプラットフォームと言語を区別することが重要だと思います。
kingfrito_5005 2015

1
確かに、Javaには確かに変数の背後にポインターがあります。これは、Javaが舞台裏で魔法をかけているため、開発者がそれらに対処する必要がないというだけのことです。これは、開発者が変数を特定のメモリアドレスに直接ポイントすること、およびデータオフセットなどを処理することを直接許可されないことを意味します。これにより、Javaはクリーンなメモリガベージコレクションを維持できますが、すべての変数は本質的にポインタであるため、自動生成されたすべてのポインタアドレスを取得するために追加のメモリが必要になります。
VulstaR

38

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

Java言語環境」の最後のポイントも参照してください。


3
ここで数少ない正解の1つに賛成票はほとんどありませんか?
2015

ポインタのような動作をシミュレートする「ポインタ」オブジェクトが存在することに注意してください。多くの目的でこれは同じように使用でき、メモリレベルのアドレス指定は耐えられません。質問の性質を考えると、誰もこれについて言及しなかったのは奇妙だと思います。
kingfrito_5005 2015

これが一番の答えになるはずです。なぜなら、「Javaの背後にはポインターがある」と初心者が言っていると、非常に混乱する状態になる可能性があるからです。Javaが初級レベルで教えられたとしても、ポインタが安全でないことが教えられているので、Javaでは使用されていません。プログラマーは、自分が何を見て作業できるかを伝える必要があります。参照とポインタは実際には大きく異なります。
Neeraj Yadav

リンクの「2.2.3 No Enums」トピックに完全に同意するかどうかは不明です。データは古くなっている可能性がありますが、Java 列挙型をサポートしています。
Sometowngeek

1
@Sometowngeekリンク先のドキュメントは、Javaの非常に最初のバージョンを説明した1996年のホワイトペーパーです。列挙型は、Javaバージョン1.5(2004)で導入されました
Fortega

11

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で実行できます。


10

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


7

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

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


8
ポインタは非常に強力で便利です。ポインタ(Java)がないとコードの効率が大幅に低下する場合が多くあります。人々がポインタを使うのが嫌いだからといって、言語がそれらを除外すべきだという意味ではありません。他の人(軍など)がライフルを使って人を殺すので、私はライフルを持っていないのですか?
イーサンリーザー

1
言語のように、Javaで実行できない便利な機能や強力な機能はあまりありません。それ以外の場合は、Unsafeクラスがあり、ほとんど使用する必要がありません。
Peter Lawrey、2012年

2
Javaにはコアとなる低レベルの機能がないため、過去40年間に私が書いたコードの多くはJavaに実装できなかったでしょう。
危険

1
@Dangerが多くのライブラリがUnsafeを使用している理由であり、それを削除するという考えはJava 9で多くの議論を巻き起こしています。
Peter Lawrey、2015

3

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


1
JNIを介していないのですか?ここで話すJavaの知識はありませんが、低レベルのビットグラビングをこの方法で実行できると聞いたと思います。
David Seiler、

私のJavaでの4年以上の経験と、自分自身で答えを探している限り、Javaポインターは外部からアクセスできません。
Poindexter

ご返信ありがとうございます。私の講師は、Javaがハンドヘルドデバイスで使用される研究レベルでと言われ、ので、私は,,彼らは...そのポインタを使用して尋ねた。私は尋ねた理由だ

@unknown(google)研究レベルの場合、何が行われているかによっては、そのような機能が必要だった可能性があるため、通常のイディオムに違反して実装しました。通常のJava機能のスーパーセット(またはサブセット、または混合)が必要な場合は、独自のJVMを実装できますが、そのようなコードは他のJavaプラットフォームでは実行できない場合があります。
サンジャシント

@san:答えてくれてありがとう。ところで私は投票できません.. 15の評判が必要だと言います

2

いいえ、違います。

Javaにはポインターがありません。あなたがいる場合、本当に欲しかったあなたは反射のようなものを周りに構築することにより、それらをエミュレートしようとすることができますが、それはすべてのだろう複雑のどれとポインタのメリットを

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


私はそれを知りたいと思っています。答えてくれてありがとう

Javaはポインターを必要とするので、JavaがJNIを追加したのはそのためです。「ポインターのような」またはより低いレベルの関数の欠如を回避するために、どんなコードを書いても、Javaでは実行できません。
危険

2

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

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

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


これは明らかに間違っています。swap2つのオブジェクトを交換する関数をJavaで作成することはできません。
Michael Tsang

2

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


1

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

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

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


1

Godfrey Nolanによる「Decompiling Android」という本から

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


0

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

ただし、Javaでリテラル値を参照渡しできるようにしたいと思います。線に沿った何か

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


-1

アドレスを保持する変数はポインターと呼ばれ、オブジェクト保持アドレス.soオブジェクトはポインター変数であるため、すべてのJavaオブジェクトはポインターです。


1
いいえ、Javaオブジェクトはポインターではありません。これらは参照と同等であり、機能とセマンティクスのセットが異なります。
危険
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.