Wie kann ich Zeiger in Java verwenden?


112

Ich weiß, dass Java keine Zeiger hat, aber ich habe gehört, dass Java-Programme mit Zeigern erstellt werden können und dass dies von den wenigen Experten in Java durchgeführt werden kann. Ist es wahr?


1
In der Implementierung von Sun sowieso.
Michael Myers

1
Kann ich diese

6
Der Standard-Hashcode für ein Java-Objekt ist NICHT die Zeigeradresse. Lesen Sie den Vertrag für Hashcode erneut sorgfältig durch, und Sie werden feststellen, dass zwei unterschiedliche Objekte im Speicher denselben Hashcode-Wert haben können.
Amir Afghani

3
In 64-Bit- und 32-Bit-Java ist der 32-Bit-Hashcode nicht die Adresse. Es wird nicht garantiert, dass hashCodes eindeutig sind. Die Position eines Objekts kann im Speicher verschoben werden, wenn es zwischen Leerzeichen verschoben wird und der Speicher komprimiert wird. Der Hashcode ändert sich jedoch nicht.
Peter Lawrey

2
90% von dem, was Sie mit C ++ - Zeigern tun können, können Sie mit Java-Aktualisierungen tun, die restlichen 10% können Sie erhalten, indem Sie eine Referenz in ein anderes Objekt packen (nicht, dass ich es jemals für notwendig gehalten hätte, dies zu tun)
Richard Tingle

Antworten:


243

Alle Objekte in Java sind Referenzen und können wie Zeiger verwendet werden.

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;

Dereferenzieren einer Null:

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

Aliasing-Problem:

third = new Tiger();
first = third;

Zellen verlieren:

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

Sie können dies sicher machen, indem Sie zunächst sicherstellen, dass der alte Wert von second nicht mehr benötigt wird, oder einem anderen Zeiger den Wert von second zuweisen.

first = second;
second = third; //OK

Beachten Sie, dass das Geben eines zweiten Werts auf andere Weise (NULL, neu ...) ebenso ein potenzieller Fehler ist und zum Verlust des Objekts führen kann, auf das es zeigt.

Das Java-System löst eine Ausnahme ( OutOfMemoryError) aus, wenn Sie new aufrufen und der Allokator die angeforderte Zelle nicht zuordnen kann. Dies ist sehr selten und resultiert normalerweise aus einer weggelaufenen Rekursion.

Beachten Sie, dass aus sprachlicher Sicht das Übergeben von Objekten an den Garbage Collector überhaupt keine Fehler sind. Es ist nur etwas, das der Programmierer beachten muss. Dieselbe Variable kann zu unterschiedlichen Zeiten auf unterschiedliche Objekte verweisen, und alte Werte werden zurückgefordert, wenn kein Zeiger auf sie verweist. Wenn die Logik des Programms jedoch die Aufrechterhaltung mindestens eines Verweises auf das Objekt erfordert, führt dies zu einem Fehler.

Anfänger machen häufig den folgenden Fehler.

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

Was Sie wahrscheinlich sagen wollten, war:

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

Unsachgemäßes Casting:

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.

Zeiger in 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
}

Zeiger in 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
    }
} 

UPDATE: Wie in den Kommentaren vorgeschlagen, muss man beachten, dass C Zeigerarithmetik hat. In Java gibt es das jedoch nicht.


16
Gute Antwort, aber Sie haben einen wesentlichen Unterschied nicht angesprochen: C hat Zeigerarithmetik. (Zum Glück) geht das in Java nicht.
R. Martinho Fernandes

10
Ich hasse es, eine Antwort herunterzustimmen, insbesondere eine, die beliebt ist, aber Java hat keine Zeiger und Sie können einfach keine Referenz wie einen Zeiger verwenden. Es gibt bestimmte Dinge, die Sie nur mit echten Zeigern tun können - zum Beispiel können Sie ein beliebiges Byte in Ihrem Prozessdatenbereich abrufen oder festlegen. In Java ist das einfach nicht möglich. Es ist wirklich schlimm, dass so viele Leute hier nicht verstehen, was ein Zeiger wirklich ist, imho, und jetzt werde ich aus meiner Seifenkiste steigen und hoffen, dass Sie mir meinen kleinen Ausbruch verzeihen.
Gefahr

5
Ich denke du meinst leider. Warum denkst du, ist es gut, dass Java keine Zeigerarithmetik unterstützt?
user3462295

2
@ user3462295 Weil die Leute zu denken scheinen, dass es zu schwierig ist, von der allgemeinen Bevölkerung verwendet zu werden, und nur durch Codierung von Ninjas, die Compiler oder Gerätetreiber schreiben, verstanden werden kann.
iCodeSometime

4
@Danger Erste Antwortzeile "Alle Objekte in Java sind Referenzen und können wie Zeiger verwendet werden." Dies ist die beste Antwort, die gegeben werden kann. Wenn die einzige Antwort "Nein, Java hat keine Zeiger" gewesen wäre. Diese Antwort wäre nicht hilfreich gewesen. Diese Antwort gibt stattdessen an, was Sie stattdessen tun können.
csga5000

46

Java hat Zeiger. Jedes Mal, wenn Sie ein Objekt in Java erstellen, erstellen Sie tatsächlich einen Zeiger auf das Objekt. Dieser Zeiger könnte dann auf ein anderes Objekt oder auf gesetzt werden null, und das ursprüngliche Objekt bleibt bestehen (ausstehende Speicherbereinigung).

Was Sie in Java nicht tun können, ist Zeigerarithmetik. Sie können eine bestimmte Speicheradresse nicht dereferenzieren oder einen Zeiger erhöhen.

Wenn Sie wirklich auf niedrigem Niveau arbeiten möchten, können Sie dies nur mit der Java Native Interface tun . und selbst dann muss der Low-Level-Teil in C oder C ++ erledigt werden.


9
Java hat schlicht und einfach keine Zeiger, und ich kann für mein ganzes Leben nicht verstehen, warum so viele Antworten hier falsche Informationen enthalten. Das sind StackOverlfow-Leute! Die Definition eines Zeigers in der Informatik lautet (Sie können dies von Google): "In der Informatik ist ein Zeiger ein Programmiersprachenobjekt, dessen Wert auf einen anderen Wert verweist (oder auf diesen zeigt"), der an anderer Stelle im Computerspeicher gespeichert ist seine Adresse. " Eine Referenz in Java ist KEIN Zeiger. Java muss die Garbage Collection ausführen und wenn Sie einen echten Zeiger hätten, wäre dies falsch!
Gefahr

3
@Danger Ein Zeiger ist ein Datenelement, das eine Speicheradresse enthält. Java ist zwei Dinge, die die Leute vergessen. Es ist eine Sprache und eine Plattform. Auch wenn man nicht sagen würde, dass .NET eine Sprache ist, müssen wir uns daran erinnern, dass die Aussage "Java hat keine Zeiger" irreführend sein kann, da die Plattform natürlich Zeiger hat und verwendet. Diese Zeiger sind für den Programmierer nicht über die Java-Sprache zugänglich, existieren jedoch zur Laufzeit. Verweise in der Sprache existieren zusätzlich zu den tatsächlichen Zeigern in der Laufzeit.
kingfrito_5005

@ kingfrito_5005 Es scheint, dass Sie mir zustimmen. Ich glaube, Sie sagten "Diese Zeiger sind für den Programmierer nicht über die Java-Sprache zugänglich", was mit meiner Aussage übereinstimmt, dass "Java keine Zeiger hat". Referenzen unterscheiden sich semantisch signifikant von Zeigern.
Gefahr

1
@Danger dies ist wahr, aber ich denke, es ist in diesen Fällen wichtig, zwischen der Plattform und der Sprache zu unterscheiden, weil ich weiß, dass mich eine Aussage wie Ihre verwirrt hätte, als ich anfing.
kingfrito_5005

1
Ja, Java hat sicherlich Zeiger hinter den Variablen. Es ist nur so, dass Entwickler sich nicht mit ihnen befassen müssen, weil Java hinter den Kulissen die Magie dafür ausübt. Dies bedeutet, dass Entwickler eine Variable nicht direkt auf eine bestimmte Speicheradresse verweisen und sich mit Datenversätzen und anderen Dingen befassen dürfen. Es ermöglicht Java, eine saubere Speicherbereinigung für Speicher zu speichern. Da jedoch jede Variable im Wesentlichen ein Zeiger ist, ist auch ein zusätzlicher Speicher erforderlich, um alle automatisch generierten Zeigeradressen zu haben, die in den niedrigeren Sprachen hätten vermieden werden können.
VulstaR

38

Da Java keine Zeigerdatentypen hat, ist es unmöglich, Zeiger in Java zu verwenden. Selbst die wenigen Experten werden in Java keine Zeiger verwenden können.

Siehe auch den letzten Punkt in: Die Java-Sprachumgebung


3
Eine der wenigen richtigen Antworten hier hat kaum positive Stimmen?
Gefahr

Beachten Sie, dass es Zeigerobjekte gibt, die ein zeigerähnliches Verhalten simulieren. Für viele Zwecke kann dies auf die gleiche Weise verwendet werden, wobei die Adressierung auf Speicherebene nicht standhält. Angesichts der Art der Frage finde ich es seltsam, dass dies niemand anderes erwähnt hat.
kingfrito_5005

Dies sollte die Antwort oben sein. Denn für Anfänger kann die Aussage, dass "Java hinter den Kulissen Zeiger hat", zu einem sehr verwirrenden Zustand führen. Selbst wenn Java auf der Anfangsebene unterrichtet wird, wird gelehrt, dass Zeiger nicht sicher sind, weshalb sie in Java nicht verwendet werden. Einem Programmierer muss gesagt werden, was er sehen und daran arbeiten kann. Referenz und Zeiger sind tatsächlich sehr unterschiedlich.
Neeraj Yadav

Ich bin mir nicht sicher, ob ich dem Thema "2.2.3 Keine Aufzählungen" im Link vollständig zustimme. Die Daten können veraltet sein, aber Java tut Unterstützung Aufzählungen.
Sometowngeek

1
@Sometowngeek Das verknüpfte Dokument ist ein Whitepaper aus dem Jahr 1996, das die allererste Version von Java beschreibt. Enums werden in Java Version 1.5 (2004) eingeführt
Fortega

11

In Java gibt es Zeiger, aber Sie können sie nicht wie in C ++ oder C bearbeiten. Wenn Sie ein Objekt übergeben, übergeben Sie einen Zeiger auf dieses Objekt, jedoch nicht im gleichen Sinne wie in C ++. Dieses Objekt kann nicht dereferenziert werden. Wenn Sie die Werte mit den nativen Zugriffsmethoden festlegen, ändert sich dies, da Java den Speicherort über den Zeiger kennt. Aber der Zeiger ist unveränderlich. Wenn Sie versuchen, den Zeiger auf einen neuen Speicherort zu setzen, erhalten Sie stattdessen ein neues lokales Objekt mit demselben Namen wie das andere. Das ursprüngliche Objekt bleibt unverändert. Hier ist ein kurzes Programm, um den Unterschied zu demonstrieren.

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;
    }
}

Dies kann auf Ideone.com ausgeführt werden.


10

Java hat keine Zeiger wie C, aber Sie können neue Objekte auf dem Heap erstellen, auf die durch Variablen "verwiesen" wird. Das Fehlen von Zeigern verhindert, dass Java-Programme illegal auf Speicherorte verweisen, und ermöglicht außerdem, dass die Garbage Collection automatisch von der Java Virtual Machine ausgeführt wird.


7

Sie können Adressen und Zeiger mit der Klasse Unsafe verwenden. Wie der Name schon sagt, sind diese Methoden UNSICHER und im Allgemeinen eine schlechte Idee. Eine falsche Verwendung kann dazu führen, dass Ihre JVM zufällig stirbt (tatsächlich führt das gleiche Problem dazu, dass Zeiger in C / C ++ falsch verwendet werden).

Während Sie vielleicht an Zeiger gewöhnt sind und denken, dass Sie sie brauchen (weil Sie nicht wissen, wie man auf andere Weise codiert), werden Sie feststellen, dass Sie dies nicht tun, und Sie werden besser dran sein.


8
Zeiger sind extrem leistungsfähig und nützlich. Es gibt viele Fälle, in denen das Fehlen von Zeigern (Java) den Code weniger effizient macht. Nur weil die Leute an der Verwendung von Zeigern scheißen, heißt das nicht, dass Sprachen sie ausschließen sollten. Sollte ich kein Gewehr haben, weil andere (wie das Militär) sie benutzen, um Menschen zu töten?
Ethan Reesor

1
Es gibt nicht viel Nützliches oder Mächtiges, was Sie in Java nicht tun können, wie die Sprache ist. Für alles andere gibt es die unsichere Klasse, die ich sehr selten verwenden muss.
Peter Lawrey

2
Ein Großteil des Codes, den ich in den letzten 40 Jahren geschrieben habe, konnte niemals in Java implementiert werden, da Java keine Kernfunktionen auf niedriger Ebene bietet.
Gefahr

1
@Danger, weshalb eine große Anzahl von Bibliotheken Unsafe verwenden und die Idee, es zu entfernen, in Java 9 so viele Debatten ausgelöst hat. Es ist geplant, Ersatz bereitzustellen, aber sie sind noch nicht fertig.
Peter Lawrey

3

Technisch gesehen sind alle Java-Objekte Zeiger. Alle primitiven Typen sind jedoch Werte. Es gibt keine Möglichkeit, diese Zeiger manuell zu steuern. Java verwendet nur intern Pass-by-Reference.


1
Nicht einmal durch JNI? Hier gibt es keine nennenswerten Java-Kenntnisse, aber ich dachte, ich hätte gehört, dass Sie auf diese Weise ein wenig Bit-Grubbing auf niedriger Ebene durchführen können.
David Seiler

Soweit meine ~ 4 Jahre Java-Erfahrung und die Suche nach der Antwort selbst Nein sagen, sind Java-Zeiger von außen nicht zugänglich.
Poindexter

Danke für die Antwort. Ich fragte, weil mein Dozent sagte, dass auf Forschungsebene, wo Java in Handheld-Geräten verwendet wird, sie Zeiger verwenden ... deshalb habe ich gefragt

@unknown (google) Wenn es sich auf Forschungsebene befindet, kann es sein, dass sie solche Funktionen benötigen, je nachdem, was gerade getan wird. Daher haben sie die normalen Redewendungen verletzt und sie trotzdem implementiert. Sie können Ihre eigene JVM implementieren, wenn Sie eine Obermenge (oder Teilmenge oder Mischung) normaler Java-Funktionen wünschen, dieser Code jedoch möglicherweise nicht auf anderen Java-Plattformen ausgeführt wird.
San Jacinto

@san: Danke für die Antwort. Übrigens kann ich nicht abstimmen. Sagt, dass ich 15 Ruf brauche

2

Nicht wirklich, nein.

Java hat keine Zeiger. Wenn Sie wirklich wollten, könnten Sie versuchen, sie zu emulieren, indem Sie sich auf etwas wie Reflexion stützen, aber es hätte die ganze Komplexität von Zeigern ohne die Vorteile .

Java hat keine Zeiger, weil es sie nicht benötigt. Auf welche Art von Antworten haben Sie von dieser Frage gehofft, dh tief im Inneren haben Sie gehofft, Sie könnten sie für etwas verwenden, oder war das nur Neugier?


Ich bin neugierig das zu wissen. Vielen Dank für die Antwort

Java benötigt Zeiger, und deshalb hat Java JNI hinzugefügt - um das Fehlen von "zeigerartigen" oder Funktionen auf niedrigerer Ebene zu umgehen, die Sie in Java einfach nicht ausführen können, unabhängig davon, welchen Code Sie schreiben.
Gefahr

2

Alle Objekte in Java werden per Referenzkopie an Funktionen übergeben, mit Ausnahme von Grundelementen.

In der Tat bedeutet dies, dass Sie eine Kopie des Zeigers auf das ursprüngliche Objekt und nicht auf eine Kopie des Objekts selbst senden.

Bitte hinterlassen Sie einen Kommentar, wenn Sie möchten, dass ein Beispiel dies versteht.


Das ist einfach falsch. Sie können swapin Java keine Funktion schreiben, die zwei Objekte austauscht.
Michael Tsang

2

Java-Referenztypen sind nicht mit C-Zeigern identisch, da Sie in Java keinen Zeiger auf einen Zeiger haben können.


1

Wie andere gesagt haben, lautet die kurze Antwort "Nein".

Sicher, Sie könnten JNI-Code schreiben, der mit Java-Zeigern spielt. Je nachdem, was Sie erreichen möchten, bringt Sie das vielleicht irgendwohin und vielleicht auch nicht.

Sie können Punkte jederzeit simulieren, indem Sie ein Array erstellen und mit Indizes im Array arbeiten. Je nachdem, was Sie erreichen möchten, kann dies wiederum nützlich sein oder auch nicht.


1

aus dem Buch Decompiling Android von Godfrey Nolan

Die Sicherheit schreibt vor, dass Zeiger in Java nicht verwendet werden, damit Hacker nicht aus einer Anwendung in das Betriebssystem eindringen können. Keine Zeiger bedeuten, dass sich etwas anderes - in diesem Fall die JVM - um das Zuweisen und Freigeben von Speicher kümmern muss. Speicherlecks sollten ebenfalls der Vergangenheit angehören, so die Theorie. Einige in C und C ++ geschriebene Anwendungen sind dafür berüchtigt, Speicher wie ein Sieb zu verlieren, da Programmierer nicht darauf achten, unerwünschten Speicher zum richtigen Zeitpunkt freizugeben ---- nicht, dass jemand, der dies liest, einer solchen Sünde schuldig wäre. Die Speicherbereinigung sollte Programmierer auch produktiver machen und weniger Zeit für das Debuggen von Speicherproblemen aufwenden.


0

Sie können auch Zeiger für Literale haben. Sie müssen sie selbst implementieren. Für Experten ist es ziemlich einfach;). Verwenden Sie ein Array aus int / object / long / byte und voila. Sie haben die Grundlagen für die Implementierung von Zeigern. Jetzt kann jeder int-Wert ein Zeiger auf dieses Array int [] sein. Sie können den Zeiger inkrementieren, Sie können den Zeiger dekrementieren, Sie können den Zeiger multiplizieren. Sie haben tatsächlich Zeigerarithmetik! Nur so können 1000 int-Attributklassen implementiert und eine generische Methode verwendet werden, die für alle Attribute gilt. Sie können auch ein Byte [] -Array anstelle eines int [] verwenden.

Ich wünschte jedoch, Java würde es Ihnen ermöglichen, Literalwerte als Referenz zu übergeben. Etwas in der Richtung

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


-1

Alle Java-Objekte sind Zeiger, da eine Variable, die die Adresse enthält, als Zeiger und das Objekt als Adresse bezeichnet wird. Das Objekt ist also eine Zeigervariable.


1
Nein, Java-Objekte sind keine Zeiger. Sie entsprechen Referenzen, die unterschiedliche Funktionen und Semantiken aufweisen.
Gefahr
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.