Как я могу использовать указатели в Java? - PullRequest
97 голосов
/ 17 ноября 2009

Я знаю, что в Java нет указателей, но я слышал, что программы на Java могут создаваться с помощью указателей, и что это могут сделать немногие, являющиеся экспертами в Java. Это правда?

Ответы [ 14 ]

232 голосов
/ 17 ноября 2009

Все объекты в 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;

Разыменование нулевого значения:

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.    

Вы можете сделать это безопасно, сначала убедившись, что больше нет необходимости в старом значении секунды, или назначив другому указателю значение секунды.

first = second;
second = third; //OK

Обратите внимание, что присвоение секунде значения другими способами (NULL, new ...) является такой же потенциальной ошибкой и может привести к потере объекта, на который она указывает.

Система Java выдает исключение (OutOfMemoryError), когда вы вызываете new, и распределитель не может выделить запрошенную ячейку. Это очень редко и обычно является результатом рекурсии бегства.

Обратите внимание, что с языковой точки зрения отказ от объектов в сборщике мусора вовсе не является ошибкой. Это просто то, что программист должен знать. Одна и та же переменная может указывать на разные объекты в разное время, и старые значения будут возвращены, когда на них не ссылается ни один указатель. Но если логика программы требует сохранения хотя бы одной ссылки на объект, это вызовет ошибку.

Новички часто делают следующую ошибку.

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 этого нет.

42 голосов
/ 17 ноября 2009

Java имеет указатели. Каждый раз, когда вы создаете объект в Java, вы фактически создаете указатель на объект; этот указатель можно затем установить для другого объекта или null, и исходный объект все еще будет существовать (ожидающий сборщик мусора).

В Java вы не можете использовать арифметику указателей. Вы не можете разыменовать определенный адрес памяти или увеличить указатель.

Если вы действительно хотите получить низкий уровень, единственный способ сделать это - собственный интерфейс Java ; и даже тогда, низкоуровневая часть должна быть сделана в C или C ++.

29 голосов
/ 17 ноября 2009

Поскольку в Java нет типов данных указателей, в Java невозможно использовать указатели. Даже немногие эксперты не смогут использовать указатели в Java.

См. Также последний пункт в: Языковая среда Java

8 голосов
/ 17 ноября 2009

В Java нет указателей, как в C, но она позволяет создавать в куче новые объекты, на которые "ссылаются" переменные. Недостаток указателей заключается в том, чтобы запретить программам Java нелегально ссылаться на области памяти, а также автоматически выполнять сборку мусора виртуальной машиной Java.

7 голосов
/ 05 августа 2015

В 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.

7 голосов
/ 06 декабря 2009

Вы можете использовать адреса и указатели, используя класс Unsafe. Однако, как следует из названия, эти методы НЕ БЕЗОПАСНЫ и вообще плохая идея. Неправильное использование может привести к случайному умиранию вашей JVM (фактически, та же проблема заключается в неправильном использовании указателей в C / C ++)

Хотя вы можете привыкнуть к указателям и думать, что они вам нужны (потому что вы не умеете кодировать каким-либо другим способом), вы обнаружите, что это не так, и вам будет лучше.

3 голосов
/ 17 ноября 2009

Все объекты в java передаются функциям посредством ссылки, кроме примитивов.

Фактически это означает, что вы отправляете копию указателя на исходный объект, а не копию самого объекта.

Пожалуйста, оставьте комментарий, если вы хотите, чтобы пример это понял.

2 голосов
/ 12 июля 2015

Типы ссылок Java не совпадают с указателями C, поскольку у вас не может быть указателя на указатель в Java.

1 голос
/ 03 апреля 2014

из книги Годфри Нолана "Декомпиляция Android"

Безопасность требует, чтобы указатели не используется в Java , чтобы хакеры не могли вырваться из приложения в операционную систему система. Отсутствие указателей означает, что что-то еще ---- в этом случае JVM ---- должно позаботьтесь о распределении и освобождении памяти. Утечки памяти должны также стать делом прошлого, или так теория уходит. Некоторые приложения написаны на C и C ++ печально известны утечкой памяти, как сито, потому что программисты не обращайте внимания на освобождение ненужной памяти в нужное время ---- не что любой, кто читает это, будет виновен в таком грехе. Вывоз мусора должен также сделать программистов более продуктивными, с меньшим количеством отладка проблем с памятью.

1 голос
/ 17 ноября 2009

Не совсем, нет.

У Java нет указателей. Если бы вы действительно хотели, вы могли бы попытаться подражать им, построив вокруг что-то вроде отражения, но у него были бы все сложность указателей без каких-либо из преимуществ .

У Java нет указателей, потому что они не нужны. На какие ответы вы надеялись ответить на этот вопрос, т. Е. В глубине души вы надеялись использовать их для чего-то или это было просто любопытство?

...