Java参照はCポインターとどのように異なりますか?


97

Cにはポインターがあり、Javaには参照と呼ばれるものがあります。彼らはすべてが何かを指しているという意味でいくつかの共通点を持っています。Cのポインターは、それらが指すアドレスを格納することを知っています。参照には住所も保存されますか?ポインターがより柔軟でエラーが発生しやすいことを除いて、それらはどのように違いますか?


10
注C ++には、ポインターまたはJava参照
jk)

@jk。Javaと同じだろうと思っていましたが、違いは何ですか?
グニジューズ

17
C ++参照は再バインドできません(つまり、指定されたオブジェクトを変更することはできません)。また、null可能ではありません(つまり、オブジェクトをまったく参照しないようにすることはできません)。
AProgrammer

@Gnijuohz @AProgrammerが言ったことを言い換えます:finalJavaでの参照は、C ++の参照とほぼ同等です。これらが完全に同等ではない理由は、C ++参照はさらにNULL可能ではありませんがfinal、Javaの参照はNULL可能です。
Utku

回答:


142

参照は、アドレスを保存することで実装できます。 通常、 Java参照はポインターとして実装されますが、仕様では必須ではありません。ガベージコレクションを容易にするために、間接的な追加のレイヤーを使用している場合があります。しかし、最終的には(ほとんどの場合)(Javaスタイルの)参照の実装に関与する(Cスタイルの)ポインターに要約されます。

参照を使用してポインター演算を行うことはできません。CのポインターとJavaの参照の最も重要な違いは、Javaの参照の基になる値に実際にアクセスできない(および操​​作できない)ことです。言い換えれば、ポインター演算を行うことはできません。

Cでは、ポインタ(つまり、アドレス)に何かを追加したり、「近く」にあるものを指すように何かを減算したり、任意の場所にある場所を指すことができます。

Javaでは、参照は1つのこととそのことだけを指します。変数に別の参照を保持させることはできますが、「元の事の後の事」を指すように変数に求めることはできません。

参照は強く型付けされています。別の違いは、Javaでは、参照の型がCのポインターの型よりもはるかに厳密に制御されることです。Cでは、を使用してint*それをキャストしchar*、その場所でメモリを再解釈できます。この再解釈はJavaでは機能しません。参照のもう一方の端にあるオブジェクトは、既にあるものとしてしか解釈できません(つまり、Object参照先のオブジェクトが実際にである場合のみ参照にString参照をキャストできます)。String

これらの違いにより、Cポインターはより強力になりますが、より危険になります。これらの可能性(ポインターの算術演算とポイントされる値の再解釈)の両方がCに柔軟性を追加し、言語の力の一部のソースです。しかし、それらは問題の大きな原因でもあります。間違って使用すると、コードが構築されているという前提を簡単に破ることができるからです。そして、それらを誤って使用するのは非常に簡単です。


18
mightの場合 +1 。実装の詳細に依存しないでください。
からCVn

2
+1ガベージコレクションは、特定の太字として言及するに値しませんか?Cポインターがより強力であるが、より危険な別の方法です(解放されたメモリーへのポインターがぶら下がってメモリー破損を引き起こす、メモリーリークのリスク)
MarkJ

参照とポインターのもう1つの違いは、Cのポインターを数字のシーケンスに変換できることです(たとえば、memcpy1 をに移動することでchar[])。逆も同様です。ポインターがどこかに保存されている数字のシーケンスに変換される場合(画面に表示され、オペレーターによって紙片にコピーされる場合があります)、コンピューター内のポインターのすべてのコピーが破壊され、その数字のシーケンスが変換されますポインターに戻る(おそらく、オペレーターによって入力された後)場合でも、ポインターは以前と同じものを指している必要があります。...プログラム
supercat

...ポインタを数字として表示し、手動で入力した数字をポインタに変換すると「悪」かもしれませんが、有効な形式を示すことが示されていない数字を入力しない限り、未定義の動作は呼び出されませんポインター。汎用ガベージコレクションは、完全に移植可能なCでは不可能です。なぜなら、ポインターのコピーが宇宙のどこかに存在する可能性があるかどうかをコンピューターが知る方法がないためです。
supercat

JLS§4.3.1によると、Javaの参照はポインターであるため、「通常Java参照はポインターとして実装されますが、仕様では必要ありません」。偽です。
ルーブロッホ

8

C ++参照は再び異なります。

初期化する必要があり、nullにすることはできません(少なくとも適切な形式のプログラムでは使用できません)。他の何かを参照するために再配置することはできません。C ++参照は、オブジェクトのエイリアスによく似ています。

ポインターとJava / C ++参照のもう1つの重要な違いは、参照のアドレスにアクセスできないポインターのアドレスを取得できることです(実際、C ++参照は実際にはメモリ内のオブジェクトとして存在する必要はありません)。ポインターへのポインター、参照への参照ではない


4

Java参照とCポインターは、正確に2つの点で異なります。

  1. 前者にはポインター演算がありません。
  2. そして、あなたが望むものへのJava参照を作成することはできません。アクセス可能な場所(静的フィールド、オブジェクトのフィールド、ローカル変数)に保存されたもの、または関数呼び出し(コンストラクター呼び出しなど)によって返されたもののみをコピーできます。したがって、これらはすべてJavaを参照しますオブジェクト(決して参照のような基本的なタイプに、charintなど)。

誰かに、参照を強く型付けすると書いた。なぜなら、コンパイラにをint*として強制的に処理させることができないからだchar*特定の変換が実際に安全である
という事実は別として、Cにはポリモーフィズムはありません。そのため、比較はスターターではありません。 確かに、JavaはCよりも強く型付けされていますが、それはCポインタとJava参照の機能ではなく、JNIを使​​用して型安全性を破る必要があります(一般的な制限を無視することを除きます)が、Cでも強制する必要がありますコンパイラ。

JVMがCで実装されている場合、 Java参照はCポインターとして実装される可能性があると書いています。64ビットマシン上では、通常、スペースと帯域幅を節約するために圧縮された通常のオブジェクトポインター(「圧縮OOP」)です。
とにかく、これらのCポインターは、通常(実装の99%以上)がパフォーマンス上の理由である場合でも、ハードウェアアドレスと同等である必要はありません。
最後に、それはプログラマに公開されていない実装の詳細です。


-1

それらはわずかに異なります。Javaでは、参照のコピーが呼び出された関数のスタックにコピーされ、呼び出し元の関数と同じオブジェクトをポイントし、そのオブジェクトを操作できるようにします。ただし、呼び出し関数が参照するオブジェクトは変更できません。

次のJavaコードを検討してください

public static void changeRValue(StringBuffer sb){
    sb = new StringBuffer("helllllo"); /*attempt to assign the reference
                                        to a new object*/
}
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer("hi");     //Create a new string buffer
    changeRValue(sb);                             //Call changeRValue
    System.out.println(sb.toString());            //Prints "hi" not "hello"
}

次に、C ++のポインターについて考えます。

void func(Dog* dog){
    *dog = Dog("hello world"); //Change the value of dog to a new object
}

int main(int argc, const char * argv[]) {
    Dog dog1("hi");                            //Create a dog object
    func(&dog1);                               //pass the address of dog
    cout << dog1.name;                         //Prints "hello world" not hi.
    return 0;
}

私は、*それがconstの犬と同様に見ることができることを加えるかもしれないと思った
Eladian

2
Javaのポイント先オブジェクトは、C ++と同じように簡単に変更できます。適切なメンバーにアクセスする必要があります。Javaはユーザー定義の演算子のオーバーロードをサポートしていないため、Javaオブジェクトには割り当て演算子がありません。Javaの欠如は、Java参照がC ++ポインターがポインター算術演算を無視するのと同じであるという事実とは何の関係もありません。
デュプリケータ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.