Bagaimana saya bisa menggunakan pointer di Java?

112

Saya tahu Java tidak memiliki pointer, tetapi saya mendengar bahwa program Java dapat dibuat dengan pointer dan ini dapat dilakukan oleh sedikit orang yang ahli di java. Benarkah

Peter Lawrey
sumber
1
Dalam implementasi Sun pula.
Michael Myers
1
dapatkah saya menggunakan alamat penunjuk itu
6
HashCode default untuk objek java BUKAN alamat penunjuk, baca ulang kontrak untuk kode hash dengan cermat dan Anda akan melihat bahwa dua objek berbeda di memori dapat memiliki nilai kode hash yang sama.
Amir Afghani
3
Di 64-bit dan 32-bit Java, 32-bit hashCode bukanlah alamatnya. kode hash tidak dijamin unik. Lokasi suatu objek dapat dipindahkan dalam memori saat berpindah antar spasi dan memori dipadatkan, namun kode hash tidak berubah.
Peter Lawrey
2
90% dari apa yang dapat Anda lakukan dengan pointer C ++ dapat Anda lakukan dengan java refences, 10% sisanya dapat Anda peroleh dengan mengemas referensi di dalam objek annother (bukan berarti saya merasa perlu melakukan itu)
Richard Tingle

Jawaban:

243

Semua objek di Java adalah referensi dan Anda dapat menggunakannya seperti pointer.

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;

Dereferensikan nol:

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

Masalah Aliasing:

third = new Tiger();
first = third;

Kehilangan Sel:

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

Anda dapat membuat ini aman dengan terlebih dahulu memastikan bahwa tidak diperlukan lagi nilai lama detik atau menetapkan nilai detik ke penunjuk lain.

first = second;
second = third; //OK

Perhatikan bahwa memberi nilai kedua dengan cara lain (NULL, new ...) sama banyaknya dengan potensi kesalahan dan dapat mengakibatkan kehilangan objek yang ditunjuknya.

Sistem Java akan memunculkan pengecualian ( OutOfMemoryError) saat Anda memanggil new dan pengalokasi tidak dapat mengalokasikan sel yang diminta. Ini sangat jarang dan biasanya hasil dari rekursi lari.

Perhatikan bahwa, dari sudut pandang bahasa, mengabaikan objek ke pengumpul sampah bukanlah kesalahan sama sekali. Itu hanyalah sesuatu yang perlu disadari oleh programmer. Variabel yang sama dapat menunjuk ke objek yang berbeda pada waktu yang berbeda dan nilai lama akan diambil kembali jika tidak ada pointer yang mereferensikannya. Tetapi jika logika program membutuhkan pemeliharaan setidaknya satu referensi ke objek, itu akan menyebabkan kesalahan.

Para pemula sering melakukan kesalahan berikut.

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

Apa yang mungkin ingin Anda katakan adalah:

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

Casting yang Tidak Tepat:

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.

Pointer di 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
}

Petunjuk di Jawa:

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: seperti yang disarankan dalam komentar, kita harus mencatat bahwa C memiliki aritmatika penunjuk. Namun, kami tidak memilikinya di Jawa.

Sajad Bahmani
sumber
16
Jawaban bagus, tetapi Anda gagal menjawab satu perbedaan utama: C memiliki aritmatika penunjuk. (Untungnya) Anda tidak dapat melakukan itu di Java.
R. Martinho Fernandes
10
Saya benci untuk tidak memberikan suara pada jawaban apa pun, terutama yang populer, tetapi Java tidak memiliki petunjuk dan Anda tidak dapat menggunakan referensi seperti penunjuk. Ada hal-hal tertentu yang hanya dapat Anda lakukan dengan pointer nyata - misalnya, Anda dapat memperoleh atau menyetel byte apa pun dalam ruang data proses Anda. Anda tidak bisa melakukannya di Java. Sungguh buruk bahwa begitu banyak orang di sini tampaknya tidak memahami apa sebenarnya penunjuk itu, imho, dan sekarang saya akan melepaskan kotak sabun kata-kata kasar saya dan berharap Anda memaafkan saya atas ledakan kecil saya.
Bahaya
5
Saya pikir maksud Anda Sayangnya. Mengapa menurut Anda bagus bahwa java tidak mendukung aritmatika pointer?
pengguna3462295
2
@ user3462295 Karena orang-orang tampaknya berpikir ini terlalu sulit untuk digunakan oleh masyarakat umum, dan hanya dapat dipahami dengan mengkodekan ninjas menulis kompiler atau driver perangkat.
iCodeSometime
4
@ Bahaya Baris pertama jawaban "Semua objek di Java adalah referensi dan Anda dapat menggunakannya seperti pointer.". Ini adalah jawaban terbaik yang bisa diberikan. Jika satu-satunya jawaban adalah "Tidak, java tidak memiliki petunjuk." jawaban itu tidak akan membantu. Jawaban ini malah menyatakan apa yang bisa Anda lakukan.
csga5000
46

Java memang memiliki petunjuk. Setiap kali Anda membuat objek di Java, Anda sebenarnya membuat penunjuk ke objek; penunjuk ini kemudian dapat disetel ke objek lain atau ke null, dan objek asli akan tetap ada (pengumpulan sampah tertunda).

Apa yang tidak dapat Anda lakukan di Java adalah aritmatika penunjuk. Anda tidak dapat mengubah alamat memori tertentu atau menaikkan penunjuk.

Jika Anda benar-benar ingin mendapatkan level rendah, satu-satunya cara untuk melakukannya adalah dengan Java Native Interface ; dan bahkan kemudian, bagian level rendah harus dilakukan dalam C atau C ++.

Michael Myers
sumber
9
Java tidak memiliki petunjuk, jelas dan sederhana, dan seumur hidup saya tidak dapat memahami mengapa begitu banyak jawaban di sini menyatakan informasi yang salah. Ini adalah orang StackOverlfow! Definisi penunjuk dalam ilmu komputer adalah (Anda dapat menggunakan Google untuk ini): "Dalam ilmu komputer, penunjuk adalah objek bahasa pemrograman, yang nilainya merujuk ke (atau" menunjuk ke ") nilai lain yang disimpan di tempat lain di memori komputer menggunakan alamatnya. " Referensi di Java BUKAN pointer. Java perlu menjalankan pengumpulan sampah dan jika Anda memiliki penunjuk yang sebenarnya maka itu salah!
Bahaya
3
@ Bahaya Penunjuk adalah bagian data yang berisi alamat memori. Jawa adalah dua hal yang sering dilupakan orang. Ini adalah bahasa dan platform. Banyak orang tidak akan mengatakan bahwa .NET adalah bahasa, kita perlu ingat bahwa mengatakan 'Java tidak memiliki petunjuk' bisa menyesatkan karena platform tentu saja memiliki dan menggunakan petunjuk. Pointer tersebut tidak dapat diakses oleh programmer melalui bahasa Java, tetapi ada pada waktu proses. Referensi dalam bahasa ada di atas petunjuk aktual dalam waktu proses.
kingfrito_5005
@ kingfrito_5005 Tampaknya Anda setuju dengan saya. Saya yakin Anda mengatakan "Petunjuk tersebut tidak dapat diakses oleh pemrogram melalui Bahasa Java" yang konsisten dengan pernyataan saya bahwa "Java tidak memiliki petunjuk". Referensi secara semantik berbeda secara signifikan dari pointer.
Bahaya
1
@Bahaya ini benar, tetapi menurut saya penting dalam kasus ini untuk membedakan antara platform dan bahasa karena saya tahu bahwa ketika saya pertama kali memulai pernyataan seperti milik Anda akan membuat saya bingung.
kingfrito_5005
1
Yup, Java pasti memiliki petunjuk di balik variabel. Hanya saja para pengembang tidak perlu berurusan dengan mereka karena java sedang melakukan keajaiban untuk ini di balik layar. Ini berarti pengembang tidak diizinkan secara langsung untuk mengarahkan variabel ke alamat memmory tertentu, dan menangani offset data dan sebagainya. Ini memungkinkan java untuk menyimpan koleksi sampah memmory yang bersih, tetapi karena setiap variabel pada dasarnya adalah sebuah penunjuk, diperlukan juga beberapa memmory tambahan untuk memiliki semua alamat penunjuk yang dibuat secara otomatis, yang dalam bahasa tingkat yang lebih rendah dapat dihindari.
VulstaR
38

Karena Java tidak memiliki tipe data pointer, tidak mungkin menggunakan pointer di Java. Bahkan beberapa ahli tidak akan bisa menggunakan pointer di java.

Lihat juga poin terakhir dalam: Lingkungan Bahasa Java

Fortega
sumber
3
Salah satu dari sedikit jawaban yang benar di sini hampir tidak memiliki suara positif?
Bahaya
Perhatikan bahwa terdapat objek 'pointer' yang mensimulasikan perilaku seperti pointer. Untuk banyak tujuan ini dapat digunakan dengan cara yang sama, pengalamatan tingkat memori tidak dapat ditahan. Mengingat sifat pertanyaannya, saya merasa aneh bahwa tidak ada orang lain yang menyebutkan ini.
kingfrito_5005
Ini harus menjadi jawaban di atas. Karena bagi pemula yang mengatakan bahwa "di balik layar java memiliki petunjuk" dapat menyebabkan keadaan yang sangat membingungkan. Bahkan ketika Java diajarkan di tingkat awal, diajarkan bahwa pointer tidak aman karena itu tidak digunakan di Java. Seorang programmer perlu diberi tahu apa yang dia bisa lihat dan kerjakan. Referensi dan petunjuk sebenarnya sangat berbeda.
Neeraj Yadav
Tidak yakin saya sepenuhnya setuju dengan topik "2.2.3 Tanpa Enum" di tautan. Data yang mungkin usang, tetapi Java tidak enum dukungan.
Someowngeek
1
@Sometowngeek dokumen yang ditautkan adalah kertas putih dari tahun 1996 yang menjelaskan versi paling pertama dari java. Enum diperkenalkan di java versi 1.5 (2004)
Fortega
11

Ada pointer di Java, tetapi Anda tidak bisa memanipulasinya seperti yang Anda bisa di C ++ atau C. Saat Anda meneruskan sebuah objek, Anda meneruskan sebuah pointer ke objek itu, tetapi tidak dalam arti yang sama seperti di C ++. Objek itu tidak dapat dibedakan. Jika Anda menyetel nilainya menggunakan pengakses aslinya, ini akan berubah karena Java mengetahui lokasi memorinya melalui penunjuk. Tapi penunjuk itu tidak bisa diubah. Saat Anda mencoba untuk mengatur penunjuk ke lokasi baru, Anda malah berakhir dengan objek lokal baru dengan nama yang sama dengan yang lain. Objek asli tidak berubah. Berikut adalah program singkat untuk menunjukkan perbedaannya.

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

Ini dapat dijalankan di Ideone.com.

kingfrito_5005
sumber
10

Java tidak memiliki pointer seperti yang dimiliki C, tetapi Java memungkinkan Anda membuat objek baru di heap yang "direferensikan" oleh variabel. Kurangnya petunjuk adalah untuk menghentikan program Java mereferensikan lokasi memori secara ilegal, dan juga memungkinkan Pengumpulan Sampah dilakukan secara otomatis oleh Mesin Virtual Java.

appshare.co
sumber
7

Anda dapat menggunakan alamat dan petunjuk menggunakan kelas Tidak aman. Namun seperti namanya, metode ini TIDAK AMAN dan biasanya ide yang buruk. Penggunaan yang salah dapat menyebabkan JVM Anda mati secara acak (sebenarnya masalah yang sama menggunakan pointer secara tidak benar di C / C ++)

Meskipun Anda mungkin terbiasa dengan petunjuk dan berpikir Anda membutuhkannya (karena Anda tidak tahu cara membuat kode dengan cara lain), Anda akan menemukan bahwa Anda tidak melakukannya dan Anda akan lebih baik karenanya.

Peter Lawrey
sumber
8
Pointer sangat kuat dan berguna. Ada banyak kasus di mana tidak memiliki pointer (Java) membuat kode menjadi kurang efisien. Hanya karena orang payah menggunakan petunjuk, bukan berarti bahasa harus mengecualikannya. Haruskah saya tidak memiliki senapan karena orang lain (seperti militer) menggunakannya untuk membunuh orang?
Ethan Reesor
1
Tidak banyak yang berguna atau kuat yang tidak dapat Anda lakukan di Java seperti bahasanya. Untuk yang lainnya ada kelas Tidak Aman yang menurut saya sangat jarang saya gunakan.
Peter Lawrey
2
Sebagian besar kode yang saya tulis selama 40 tahun terakhir tidak akan pernah dapat diterapkan di Java, karena Java kekurangan inti, kemampuan tingkat rendah.
Bahaya
1
@Danger itulah sebabnya sejumlah besar pustaka menggunakan Unsafe dan gagasan untuk menghapusnya telah memicu begitu banyak perdebatan di Java 9. Rencananya adalah menyediakan pengganti, tetapi mereka belum siap.
Peter Lawrey
3

Secara teknis, semua objek Java adalah pointer. Semua tipe primitif adalah nilai. Tidak ada cara untuk mengambil kendali manual atas petunjuk tersebut. Java secara internal hanya menggunakan pass-by-reference.

Poindexter
sumber
1
Bahkan tidak melalui JNI? Tidak ada pengetahuan Java untuk dibicarakan di sini, tapi saya pikir saya pernah mendengar Anda bisa melakukan beberapa grubbing tingkat rendah dengan cara itu.
David Seiler
Sejauh ~ 4 tahun pengalaman saya di Java dan mencari jawabannya sendiri mengatakan tidak, pointer Java tidak dapat diakses secara eksternal.
Poindexter
Terima kasih atas tanggapannya. Saya bertanya karena, dosen saya mengatakan bahwa pada tingkat penelitian di mana java digunakan dalam perangkat genggam`` mereka menggunakan pointer ... itulah mengapa saya bertanya
@unknown (google) jika itu pada tingkat penelitian, tergantung pada apa yang sedang dilakukan, mungkin mereka membutuhkan fungsi seperti itu, jadi mereka melanggar idiom normal dan tetap menerapkannya. Anda dapat mengimplementasikan JVM Anda sendiri jika Anda ingin memiliki superset (atau subset, atau campuran) dari fitur Java normal, tetapi kode tersebut tidak dapat berjalan di platform Java lainnya.
San Jacinto
@ san: Terima kasih atas jawabannya. BTW Saya tidak dapat memilih .. mengatakan bahwa saya perlu 15 reputasi
2

Tidak juga, tidak.

Java tidak memiliki petunjuk. Jika Anda benar - benar menginginkannya, Anda dapat mencoba meniru mereka dengan membangun di sekitar sesuatu seperti refleksi, tetapi itu akan memiliki semua kerumitan petunjuk tanpa ada manfaatnya .

Java tidak memiliki pointer karena tidak membutuhkannya. Jawaban apa yang Anda harapkan dari pertanyaan ini, yaitu jauh di lubuk hati Anda berharap dapat menggunakannya untuk sesuatu atau apakah ini hanya sekedar keingintahuan?

Andrzej Doyle
sumber
Saya penasaran untuk mengetahuinya. Terima kasih atas jawabannya
Java memang membutuhkan pointer, dan itulah mengapa Java menambahkan JNI - untuk mengatasi kekurangan "pointer-like" atau fungsi tingkat yang lebih rendah yang tidak dapat Anda lakukan di Java, apa pun kode yang Anda tulis.
Bahaya
2

Semua objek di java diteruskan ke fungsi dengan salinan referensi kecuali primitif.

Akibatnya, ini berarti Anda mengirim salinan penunjuk ke objek asli daripada salinan dari objek itu sendiri.

Silakan tinggalkan komentar jika Anda ingin contoh untuk memahami ini.

coolest_head
sumber
Ini jelas salah. Anda tidak dapat menulis swapfungsi di Java yang akan menukar dua objek.
Michael Tsang
2

Tipe referensi Java tidak sama dengan pointer C karena Anda tidak bisa memiliki pointer ke pointer di Java.

zezba9000
sumber
1

Seperti yang dikatakan orang lain, jawaban singkatnya adalah "Tidak".

Tentu, Anda dapat menulis kode JNI yang memutar dengan pointer Java. Bergantung pada apa yang Anda coba capai, mungkin itu akan membawa Anda ke suatu tempat dan mungkin tidak.

Anda selalu bisa mensimulasikan poin dengan membuat array dan bekerja dengan indeks ke dalam array. Sekali lagi, tergantung pada apa yang Anda coba capai, itu mungkin berguna atau tidak.

Jay
sumber
1

dari buku bernama Decompiling Android oleh Godfrey Nolan

Keamanan menentukan bahwa pointer tidak digunakan di Java sehingga peretas tidak dapat keluar dari aplikasi dan masuk ke sistem operasi. Tidak ada petunjuk berarti bahwa sesuatu yang lain ---- dalam hal ini, JVM ---- harus mengurus alokasi dan membebaskan memori. Kebocoran memori juga harus menjadi bagian dari masa lalu, atau begitulah menurut teori. Beberapa aplikasi yang ditulis dalam C dan C ++ terkenal merusak memori seperti saringan karena pemrogram tidak memperhatikan untuk membebaskan memori yang tidak diinginkan pada waktu yang tepat ---- bukan berarti siapa pun yang membaca ini akan bersalah melakukan dosa seperti itu. Pengumpulan sampah juga akan membuat pemrogram lebih produktif, dengan lebih sedikit waktu yang dihabiskan untuk men-debug masalah memori.

Mustafa Güven
sumber
0

Anda juga bisa mendapatkan petunjuk untuk literal. Anda harus menerapkannya sendiri. Ini cukup mendasar untuk para ahli;). Gunakan array int / object / long / byte dan voila Anda memiliki dasar-dasar untuk mengimplementasikan pointer. Sekarang nilai int apa pun bisa menjadi penunjuk ke array itu int []. Anda bisa menambah penunjuk, Anda bisa mengurangi penunjuk, Anda bisa menggandakan penunjuk. Anda memang memiliki aritmatika penunjuk! Itulah satu-satunya cara untuk mengimplementasikan 1000 kelas atribut int dan memiliki metode umum yang berlaku untuk semua atribut. Anda juga bisa menggunakan array byte [] daripada int []

Namun saya berharap Java akan membiarkan Anda meneruskan nilai literal dengan referensi. Sesuatu di sepanjang garis

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

Mordan
sumber
-1

Semua objek java adalah pointer karena variabel yang menyimpan alamat disebut pointer dan objek memegang alamat. Jadi objek adalah variabel pointer.

Krishna Kant
sumber
1
Tidak, objek Java bukanlah pointer. Mereka setara dengan referensi, yang memiliki kumpulan kapabilitas dan semantik yang berbeda.
Bahaya