Làm cách nào để sử dụng con trỏ trong Java?


112

Tôi biết Java không có con trỏ, nhưng tôi nghe nói rằng các chương trình Java có thể được tạo bằng con trỏ và điều này có thể được thực hiện bởi một số ít chuyên gia về java. Có đúng không?


1
Trong thực hiện của Sun anyway.
Michael Myers

1
tôi có thể sử dụng địa chỉ con trỏ

6
Mã băm mặc định cho một đối tượng java KHÔNG phải là địa chỉ con trỏ, hãy đọc lại hợp đồng cho Mã băm một cách cẩn thận và bạn sẽ nhận thấy rằng hai đối tượng riêng biệt trong bộ nhớ có thể có cùng giá trị Mã băm.
Amir Afghanistan

3
Trong Java 64 bit và 32 bit, mã băm 32 bit không phải là địa chỉ. Mã băm không được đảm bảo là duy nhất. Vị trí của một đối tượng có thể được di chuyển trong bộ nhớ khi nó di chuyển giữa các không gian và bộ nhớ được nén lại, tuy nhiên, mã băm không thay đổi.
Peter Lawrey

2
90% những gì bạn có thể làm với con trỏ C ++ mà bạn có thể làm với java refrences, 10% còn lại bạn có thể đạt được bằng cách đóng gói một tham chiếu bên trong một đối tượng khác (không phải là tôi đã từng thấy cần thiết để làm điều đó)
Richard Tingle

Câu trả lời:


243

Tất cả các đối tượng trong Java đều là tham chiếu và bạn có thể sử dụng chúng như con trỏ.

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;

Tham chiếu giá trị rỗng:

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

Vấn đề về răng cưa:

third = new Tiger();
first = third;

Mất tế bào:

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

Bạn có thể làm cho điều này an toàn bằng cách trước tiên đảm bảo rằng không cần thêm giá trị cũ của thứ hai hoặc chỉ định một con trỏ khác giá trị của thứ hai.

first = second;
second = third; //OK

Lưu ý rằng việc cung cấp giá trị thứ hai theo những cách khác (NULL, mới ...) cũng là một lỗi tiềm ẩn và có thể dẫn đến mất đối tượng mà nó trỏ tới.

Hệ thống Java sẽ ném một ngoại lệ ( OutOfMemoryError) khi bạn gọi mới và bộ cấp phát không thể cấp phát ô được yêu cầu. Điều này rất hiếm và thường là kết quả của đệ quy bỏ chạy.

Lưu ý rằng, từ quan điểm ngôn ngữ, việc bỏ các đối tượng vào trình thu gom rác không phải là lỗi. Nó chỉ là một cái gì đó mà các lập trình viên cần phải lưu ý. Cùng một biến có thể trỏ đến các đối tượng khác nhau tại các thời điểm khác nhau và các giá trị cũ sẽ được lấy lại khi không có con trỏ nào tham chiếu đến chúng. Nhưng nếu logic của chương trình yêu cầu duy trì ít nhất một tham chiếu đến đối tượng, Nó sẽ gây ra lỗi.

Những người mới làm quen thường mắc lỗi sau.

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

Điều bạn có thể muốn nói là:

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

Đúc không đúng:

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.

Con trỏ trong 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
}

Con trỏ trong 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ẬP NHẬT: như được đề xuất trong các ý kiến, người ta phải lưu ý rằng C có số học con trỏ. Tuy nhiên, chúng tôi không có điều đó trong Java.


16
Câu trả lời hay, nhưng bạn không giải quyết được một điểm khác biệt chính: C có số học con trỏ. (May mắn thay) bạn không thể làm điều đó trong Java.
R. Martinho Fernandes

10
Tôi ghét bỏ phiếu bất kỳ câu trả lời nào, đặc biệt là một câu trả lời phổ biến, nhưng Java không có con trỏ và bạn chỉ đơn giản là không thể sử dụng một tham chiếu như con trỏ. Có một số điều bạn chỉ có thể làm với con trỏ thực - ví dụ: bạn có thể lấy hoặc đặt bất kỳ byte nào trong không gian dữ liệu quy trình của mình. Đơn giản là bạn không thể làm điều đó trong Java. Thật là tệ khi rất nhiều người ở đây dường như không hiểu con trỏ thực sự là gì, imho, và bây giờ tôi sẽ lấy hộp xà phòng rant của mình ra và mong bạn tha thứ cho sự bộc phát nhỏ của tôi.
Nguy hiểm

5
Tôi nghĩ bạn có nghĩa là Thật không may. Tại sao bạn nghĩ rằng java không hỗ trợ số học con trỏ là tốt?
user3462295

2
@ user3462295 Bởi vì mọi người nghĩ rằng nó quá khó để được phổ biến rộng rãi sử dụng và chỉ có thể hiểu được bằng cách viết mã các ninja viết trình biên dịch hoặc trình điều khiển thiết bị.
iCodeSometime

4
@Danger Dòng đầu tiên của câu trả lời "Tất cả các đối tượng trong Java đều là tham chiếu và bạn có thể sử dụng chúng như con trỏ.". Đây là câu trả lời tốt nhất có thể được cung cấp. Nếu câu trả lời duy nhất là "Không, java không có con trỏ." câu trả lời đó sẽ không hữu ích. Thay vào đó, câu trả lời này nêu rõ bạn có thể làm gì.
csga5000,

46

Java không có con trỏ. Bất cứ khi nào bạn tạo một đối tượng trong Java, bạn thực sự đang tạo một con trỏ tới đối tượng; con trỏ này sau đó có thể được đặt thành một đối tượng khác hoặc thành null, và đối tượng ban đầu sẽ vẫn tồn tại (đang chờ thu gom rác).

Những gì bạn không thể làm trong Java là số học con trỏ. Bạn không thể bỏ qua một địa chỉ bộ nhớ cụ thể hoặc gia tăng một con trỏ.

Nếu bạn thực sự muốn có được mức thấp, cách duy nhất để làm điều đó là với Giao diện Bản địa Java ; và thậm chí sau đó, phần cấp thấp phải được thực hiện bằng C hoặc C ++.


9
Java chỉ đơn giản là không có con trỏ, đơn giản và đơn giản, và tôi không thể hiểu được tại sao rất nhiều câu trả lời ở đây nêu thông tin không chính xác. Đây là người của StackOverlfow! Định nghĩa về con trỏ trong khoa học máy tính là (bạn có thể Google để biết điều này): "Trong khoa học máy tính, con trỏ là một đối tượng ngôn ngữ lập trình, có giá trị đề cập đến (hoặc" trỏ tới ") một giá trị khác được lưu trữ ở nơi khác trong bộ nhớ máy tính bằng cách sử dụng địa chỉ của nó. " Tham chiếu trong Java KHÔNG phải là một con trỏ. Java cần phải chạy bộ sưu tập rác và nếu bạn có một con trỏ thực thì nó sẽ sai!
Nguy hiểm

3
@Danger Con trỏ là một đoạn dữ liệu chứa địa chỉ bộ nhớ. Java là hai thứ mà mọi người quên mất. Nó là một ngôn ngữ và một nền tảng. Nhiều người sẽ không nói rằng .NET là một ngôn ngữ, chúng ta cần nhớ rằng nói 'Java không có con trỏ' có thể gây hiểu lầm vì nền tảng dĩ nhiên có và sử dụng con trỏ. Các con trỏ đó không thể truy cập được đối với lập trình viên thông qua ngôn ngữ Java, nhưng chúng tồn tại trong thời gian chạy. Tham chiếu bằng ngôn ngữ tồn tại trên đầu con trỏ thực tế trong thời gian chạy.
kingfrito_5005

@ kingfrito_5005 Có vẻ như bạn đang đồng ý với tôi. Tôi tin rằng bạn đã nói "Lập trình viên không thể truy cập những con trỏ đó thông qua Ngôn ngữ Java", điều này phù hợp với tuyên bố của tôi rằng "Java không có con trỏ". Các tham chiếu khác biệt đáng kể về mặt ngữ nghĩa so với con trỏ.
Nguy hiểm

1
@Danger điều này đúng, nhưng tôi nghĩ điều quan trọng trong những trường hợp này là phân biệt giữa nền tảng và ngôn ngữ bởi vì tôi biết rằng khi tôi lần đầu tiên bắt đầu một tuyên bố như của bạn sẽ khiến tôi bối rối.
kingfrito_5005

1
Đúng vậy, Java chắc chắn có con trỏ đằng sau các biến. Nó chỉ là các nhà phát triển không phải đối phó với chúng vì java đang làm điều kỳ diệu cho điều này đằng sau hậu trường. Điều này có nghĩa là các nhà phát triển không được phép trực tiếp trỏ một biến đến một địa chỉ bộ nhớ cụ thể và xử lý các nội dung và lỗi sai lệch dữ liệu. Nó cho phép java giữ một bộ sưu tập rác bộ nhớ sạch sẽ, nhưng vì mọi biến đều cần thiết là một con trỏ, nên nó cũng cần thêm một số bộ nhớ để có tất cả các địa chỉ con trỏ được tạo tự động, điều này có thể tránh được trong các ngôn ngữ cấp thấp hơn.
VulstaR

38

Vì Java không có kiểu dữ liệu con trỏ nên không thể sử dụng con trỏ trong Java. Ngay cả một số chuyên gia sẽ không thể sử dụng con trỏ trong java.

Xem thêm điểm cuối cùng trong: Môi trường ngôn ngữ Java


3
Một trong số ít câu trả lời đúng ở đây hầu như không có bất kỳ ủng hộ nào?
Nguy hiểm

Lưu ý rằng tồn tại các đối tượng 'con trỏ' mô phỏng hành vi giống con trỏ. Đối với nhiều mục đích, điều này có thể được sử dụng theo cùng một cách, không chịu được địa chỉ cấp bộ nhớ. Với bản chất của câu hỏi, tôi cảm thấy thật kỳ lạ khi không ai khác đề cập đến điều này.
kingfrito_5005

Đây phải là câu trả lời ở trên cùng. Bởi vì đối với người mới bắt đầu nói rằng "đằng sau java có con trỏ" có thể dẫn đến trạng thái rất khó hiểu. Ngay cả khi Java được dạy ở cấp độ bắt đầu, người ta dạy rằng con trỏ không an toàn, đó là lý do tại sao chúng không được sử dụng trong Java. Một lập trình viên cần được cho biết những gì anh / cô ấy có thể nhìn thấy và làm việc. Tham chiếu và con trỏ thực sự rất khác nhau.
Neeraj Yadav

Không chắc tôi hoàn toàn đồng ý với chủ đề "2.2.3 Không có Enums" trong liên kết. Các dữ liệu có thể bị lỗi thời, nhưng Java không enums hỗ trợ.
Sometowngeek

1
@Sometowngeek tài liệu được liên kết tới là một sách trắng từ năm 1996 mô tả phiên bản java đầu tiên. Enums được giới thiệu trong java phiên bản 1.5 (2004)
Fortega

11

Có những con trỏ trong Java, nhưng bạn không thể thao tác chúng theo cách mà bạn có thể làm trong C ++ hoặc C. Khi bạn truyền một đối tượng, bạn đang truyền một con trỏ đến đối tượng đó, nhưng không theo nghĩa giống như trong C ++. Đối tượng đó không thể được tham chiếu. Nếu bạn đặt các giá trị của nó bằng cách sử dụng các bộ truy cập gốc của nó, nó sẽ thay đổi vì Java biết vị trí bộ nhớ của nó thông qua con trỏ. Nhưng con trỏ là bất biến. Khi bạn cố gắng đặt con trỏ đến một vị trí mới, thay vào đó bạn sẽ nhận được một đối tượng cục bộ mới có cùng tên với đối tượng kia. Vật ban đầu không đổi. Đây là một chương trình ngắn gọn để chứng minh sự khác biệt.

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

Điều này có thể được chạy tại Ideone.com.


10

Java không có các con trỏ như C có, nhưng nó cho phép bạn tạo các đối tượng mới trên heap được các biến "tham chiếu". Việc thiếu con trỏ là ngăn các chương trình Java tham chiếu đến các vị trí bộ nhớ một cách bất hợp pháp, đồng thời cũng cho phép Máy ảo Java tự động thực hiện Thu dọn rác.


7

Bạn có thể sử dụng địa chỉ và con trỏ bằng cách sử dụng lớp Không an toàn. Tuy nhiên, như tên cho thấy, những phương pháp này KHÔNG AN TOÀN và nói chung là một ý tưởng tồi. Việc sử dụng không đúng cách có thể dẫn đến việc JVM của bạn chết ngẫu nhiên (thực tế là cùng một vấn đề là sử dụng con trỏ không chính xác trong C / C ++)

Mặc dù bạn có thể đã quen với các con trỏ và nghĩ rằng bạn cần chúng (vì bạn không biết cách viết mã theo bất kỳ cách nào khác), bạn sẽ thấy rằng bạn không làm như vậy và bạn sẽ tốt hơn cho nó.


8
Con trỏ cực kỳ mạnh mẽ và hữu ích. Có nhiều trường hợp không có con trỏ (Java) làm cho mã kém hiệu quả hơn nhiều. Chỉ vì mọi người không thích sử dụng con trỏ không có nghĩa là ngôn ngữ nên loại trừ chúng. Tôi có nên không có súng trường vì những người khác (như quân đội) sử dụng chúng để giết người không?
Ethan Reesor

1
Không có gì hữu ích hoặc mạnh mẽ mà bạn không thể làm trong Java như ngôn ngữ này. Đối với mọi thứ khác, có lớp Không an toàn mà tôi thấy rất hiếm khi cần sử dụng.
Peter Lawrey

2
Phần lớn mã mà tôi đã viết trong 40 năm qua có thể không bao giờ được triển khai bằng Java, vì Java thiếu các khả năng cốt lõi, cấp thấp.
Nguy hiểm vào

1
@Danger đó là lý do tại sao một số lượng lớn các thư viện sử dụng Unsafe và ý tưởng loại bỏ nó đã gây ra rất nhiều tranh luận trong Java 9. Kế hoạch là cung cấp các thay thế, nhưng chúng vẫn chưa sẵn sàng.
Peter Lawrey,

3

Về mặt kỹ thuật, tất cả các đối tượng Java đều là con trỏ. Tất cả các kiểu nguyên thủy đều là giá trị. Không có cách nào để kiểm soát thủ công các con trỏ đó. Java chỉ sử dụng tham chiếu nội bộ.


1
Thậm chí không thông qua JNI? Không có kiến ​​thức Java để nói ở đây, nhưng tôi nghĩ rằng tôi đã nghe nói rằng bạn có thể thực hiện một số bit-grubbing cấp thấp theo cách đó.
David Seiler

Theo như ~ 4 năm kinh nghiệm Java của tôi và tự mình tìm kiếm câu trả lời thì nói là không, con trỏ Java không thể truy cập từ bên ngoài.
Poindexter

Cảm ơn cho phản ứng. Tôi hỏi vì, giảng viên của tôi nói rằng ở mức độ nghiên cứu nơi java sử dụng trong các thiết bị cầm tay ,, họ sử dụng con trỏ ... đó; lý do tại sao tôi hỏi

@unknown (google) nếu nó ở cấp độ nghiên cứu, tùy thuộc vào những gì đang được thực hiện, có thể họ cần chức năng như vậy, vì vậy họ đã vi phạm các thành ngữ thông thường và thực hiện chúng. Bạn có thể triển khai JVM của riêng mình nếu bạn muốn có một tập hợp siêu (hoặc tập hợp con hoặc hỗn hợp) các tính năng Java bình thường, nhưng mã như vậy có thể không chạy trên các nền tảng Java khác.
San Jacinto

@san: Cảm ơn vì câu trả lời. BTW Tôi không thể bỏ phiếu..nói rằng tôi cần 15 danh tiếng

2

Không thực sự, không.

Java không có con trỏ. Nếu bạn thực sự muốn, bạn có thể thử mô phỏng chúng bằng cách xây dựng xung quanh một cái gì đó giống như phản chiếu, nhưng nó sẽ có tất cả sự phức tạp của con trỏ mà không có lợi ích nào .

Java không có con trỏ vì nó không cần chúng. Bạn hy vọng loại câu trả lời nào từ câu hỏi này, tức là trong sâu thẳm bạn hy vọng mình có thể sử dụng chúng cho việc gì đó hay đây chỉ là sự tò mò?


Tôi tò mò muốn biết điều đó. Cảm ơn cho câu trả lời

Java cần con trỏ, và đó là lý do tại sao Java thêm JNI - để tránh việc thiếu các hàm "giống con trỏ" hoặc cấp thấp hơn mà bạn không thể thực hiện trong Java, bất kể bạn viết mã gì.
Nguy hiểm vào

2

Tất cả các đối tượng trong java được chuyển tới các hàm bằng bản sao tham chiếu ngoại trừ các đối tượng nguyên thủy.

Trên thực tế, điều này có nghĩa là bạn đang gửi một bản sao của con trỏ tới đối tượng gốc chứ không phải là bản sao của chính đối tượng.

Vui lòng để lại bình luận nếu bạn muốn một ví dụ để hiểu điều này.


Điều này rõ ràng là sai. Bạn không thể viết một swaphàm trong Java sẽ hoán đổi hai đối tượng.
Michael Tsang

2

Các kiểu tham chiếu Java không giống như con trỏ C vì bạn không thể có một con trỏ tới một con trỏ trong Java.


1

Như những người khác đã nói, câu trả lời ngắn gọn là "Không".

Chắc chắn, bạn có thể viết mã JNI chơi với con trỏ Java. Tùy thuộc vào những gì bạn đang cố gắng hoàn thành, có thể điều đó sẽ đưa bạn đến đâu đó và có thể không.

Bạn luôn có thể mô phỏng các điểm bằng cách tạo một mảng và làm việc với các chỉ mục trong mảng. Một lần nữa, tùy thuộc vào những gì bạn đang cố gắng hoàn thành, điều đó có thể hữu ích hoặc không.


1

từ cuốn sách có tên Giải mã Android của Godfrey Nolan

Bảo mật quy định rằng con trỏ không được sử dụng trong Java nên tin tặc không thể thoát ra khỏi ứng dụng và xâm nhập vào hệ điều hành. Không có con trỏ nào có nghĩa là thứ gì đó khác ---- trong trường hợp này, JVM ---- phải đảm nhận việc cấp phát và giải phóng bộ nhớ. Rò rỉ bộ nhớ cũng nên trở thành dĩ vãng, hoặc lý thuyết là vậy. Một số ứng dụng được viết bằng C và C ++ nổi tiếng với việc làm rò rỉ bộ nhớ như một cái rây bởi vì các lập trình viên không chú ý đến việc giải phóng bộ nhớ không mong muốn vào thời điểm thích hợp ---- không phải bất kỳ ai đọc nó sẽ phạm tội như vậy. Việc thu gom rác cũng sẽ làm cho các lập trình viên làm việc năng suất hơn, với ít thời gian hơn để gỡ lỗi các vấn đề về bộ nhớ.


0

bạn cũng có thể có con trỏ cho các chữ. Bạn phải tự mình thực hiện chúng. Nó là khá cơ bản cho các chuyên gia;). Sử dụng một mảng int / object / long / byte và bạn đã có những kiến ​​thức cơ bản để triển khai con trỏ. Bây giờ bất kỳ giá trị int nào cũng có thể là một con trỏ tới mảng int [] đó. Bạn có thể tăng con trỏ, bạn có thể giảm con trỏ, bạn có thể nhân con trỏ. Bạn thực sự có số học con trỏ! Đó là cách duy nhất để triển khai 1000 lớp thuộc tính int và có một phương thức chung áp dụng cho tất cả các thuộc tính. Bạn cũng có thể sử dụng một mảng [] byte thay vì một int []

Tuy nhiên, tôi ước gì Java sẽ cho phép bạn chuyển các giá trị theo nghĩa đen bằng cách tham chiếu. Một cái gì đó dọc theo dòng

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


-1

Tất cả các đối tượng java đều là con trỏ vì một biến chứa địa chỉ được gọi là con trỏ và đối tượng giữ địa chỉ. Vì vậy đối tượng là biến con trỏ.


1
Không, các đối tượng Java không phải là con trỏ. Chúng tương đương với các tham chiếu, có một tập hợp các khả năng và ngữ nghĩa khác nhau.
Nguy hiểm
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.