Javaにはポインターがないことは知っていますが、Javaプログラムはポインターを使用して作成でき、これはJavaの専門家である少数の人が作成できると聞きました。それは本当ですか?
15 に答える
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
2番目に他の方法(NULL、new ...)で値を与えることは、潜在的なエラーと同じくらい多く、それが指すオブジェクトを失う可能性があることに注意してください。
OutOfMemoryError
newを呼び出し、アロケータが要求されたセルを割り当てることができない場合、Javaシステムは例外()をスローします。これは非常にまれであり、通常、暴走した再帰が原因です。
言語の観点から、ガベージコレクターにオブジェクトを放棄することはまったくエラーではないことに注意してください。これは、プログラマーが知っておく必要のあることです。同じ変数が異なる時間に異なるオブジェクトを指す可能性があり、ポインタがそれらを参照していない場合、古い値が再利用されます。ただし、プログラムのロジックでオブジェクトへの参照を少なくとも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にはありません。
Javaにはポインタデータ型がないため、Javaでポインタを使用することはできません。少数の専門家でさえ、Javaでポインタを使用することはできません。
の最後のポイントも参照してください:Java言語環境
Java にはポインターがあります。Java でオブジェクトを作成するときはいつでも、実際にはオブジェクトへのポインタを作成しています。このポインターは、別のオブジェクトまたは に設定できnull
、元のオブジェクトは引き続き存在します (ガベージ コレクションが保留中)。
Java でできないのはポインタ演算です。特定のメモリ アドレスを逆参照したり、ポインターをインクリメントしたりすることはできません。
本当に低レベルになりたい場合、それを行う唯一の方法はJava Native Interfaceを使用することです。それでも、低レベルの部分は C または C++ で行う必要があります。
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 で実行できます。
Java には C のようなポインターはありませんが、変数によって「参照」される新しいオブジェクトをヒープ上に作成できます。ポインターの欠如は、Java プログラムがメモリ位置を不正に参照するのを防ぎ、Java 仮想マシンによるガベージ コレクションの自動実行を可能にします。
Unsafeクラスを使用してアドレスとポインタを使用できます。ただし、名前が示すように、これらの方法は安全ではなく、一般的には悪い考えです。誤った使用法では、JVMがランダムに停止する可能性があります(実際には、C / C ++でポインターを誤って使用すると同じ問題が発生します)
ポインターに慣れていて、ポインターが必要だと思うかもしれませんが(他の方法でコーディングする方法がわからないため)、そうでないことに気付くでしょう。
技術的には、すべてのJavaオブジェクトはポインターです。ただし、すべてのプリミティブ型は値です。これらのポインタを手動で制御する方法はありません。Javaは、内部的に参照渡しを使用します。
そうではありません。
Javaにはポインタがありません。本当に必要な場合は、リフレクションのようなものを中心に構築することでそれらをエミュレートすることができますが、ポインターの複雑さはすべてあり、利点はありません。
Javaはポインタを必要としないため、ポインタを持っていません。この質問からどのような答えを期待していましたか。つまり、それらを何かに使用できることを望んでいましたか、それとも単なる好奇心でしたか。
Java のすべてのオブジェクトは、プリミティブを除き、参照コピーによって関数に渡されます。
実際には、これは、オブジェクト自体のコピーではなく、元のオブジェクトへのポインターのコピーを送信していることを意味します。
これを理解するための例が必要な場合は、コメントを残してください。
他の人が言ったように、短い答えは「いいえ」です。
もちろん、Java ポインターを操作する JNI コードを作成することもできます。あなたが達成しようとしていることに応じて、おそらくそれはあなたをどこかに連れて行くかもしれませんし、そうでないかもしれません.
配列を作成し、配列へのインデックスを操作することで、いつでもポイントをシミュレートできます。繰り返しますが、達成しようとしていることに応じて、それが役立つ場合とそうでない場合があります。
Godfrey Nolan 著 Decompiling Android という本から
ハッカーがアプリケーションからオペレーティング システムに侵入できないように、Java ではポインターを使用しないことがセキュリティで規定されています。ポインタがないということは、別の何か -- この場合は JVM -- がメモリの割り当てと解放を処理する必要があることを意味します。メモリリークも過去のものになるはずです。理論的にはそうです。C および C++ で作成された一部のアプリケーションは、ふるいのようにメモリ リークが発生することで有名です。これは、プログラマが不要なメモリを適切なタイミングで解放することに注意を払っていないためです。また、ガベージ コレクションによって、メモリの問題のデバッグに費やす時間が短縮され、プログラマの生産性が向上するはずです。
リテラルへのポインターも使用できます。それらを自分で実装する必要があります。専門家にとってはかなり基本的なものです;)。int/object/long/byte の配列を使用すると、ポインタを実装するための基本ができました。これで、任意の int 値をその配列 int[] へのポインターにすることができます。ポインターをインクリメントすることも、ポインターをデクリメントすることも、ポインターを乗算することもできます。あなたは確かにポインター演算を持っています! これが、1000 個の int 属性クラスを実装し、すべての属性に適用される汎用メソッドを持つ唯一の方法です。int[] の代わりに byte[] 配列を使用することもできます
ただし、Java でリテラル値を参照渡しできるようにしてほしいと思います。線に沿った何か
//(* telling you it is a pointer)
public void myMethod(int* intValue);