Как работают Java "указатели"?

допустим, это код C++:

void change(int& x){
    x++;
}

или

void change2(int* a){
    *a++;
}

оба изменят глобальный x, верно?

Итак, как я могу сделать что-то подобное на java?
В частности, я хочу указать на векторный объект

Но поскольку Java не имеет указателей, я не уверен, что делать.
Из поиска в Интернете я видел людей, говорящих, что Java делает это каким-то другим способом, но я не нашел никакого реального примера.

Спасибо за помогите!

6 ответов


в Java вместо указателей у вас есть ссылки на объекты. Вы не можете передать примитивный тип по ссылке, но вы можете обернуть примитивный тип внутри объекта, а затем передать ссылку на этот объект.

Java предоставляет тип Integer который обертывает int, однако этот тип является неизменяемым, поэтому вы не можете изменить его значение после построения. Однако вы можете использовать MutableInt из Apache Commons:

void change(MutableInt x) {
    x.increment();
}

изменение на x будет видно абонент.


в частности, я хочу указать на векторный объект

когда вы пишите Vector v = ...; назначается ссылка вектору переменной v. Ссылка в Java очень похожа на указатель. Ссылки фактически реализуются внутри с помощью указателей.

Java использует pass by value. Когда вы передаете вектор методу, вы фактически копируете ссылка этого вектора. Он не клонирует сам вектор. Поэтому передача ссылки на Java очень похожа на передачу указателя на C++.


С Java вы не можете передавать примитивные типы, такие как int по ссылке, они передаются только по значению.

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

используйте массив одного значения, например

int[] value = new int[1];
value[0] = 2;

// call a method
obj.setValue(value);

// and in setValue
public void setValue(int[] value) {
  value[0] = 5;
}

или второй подход используйте класс держателя:

public class Holder<T> {
  public T value;
  public Holder(T value) {
    this.value = value;
  }
}

// then use it in this way
Holder<Integer> h = new Holder<Integer>(2);

obj.setValue(h);

// and in setValue
public void setValue(Holder<Integer> h) {
  h.value = 5;
}

в этом случае я использую класс holder реализует с дженериками, но вы можете иметь простой держатель тоже только для целых. Например:

public class IntHolder {
  public int value;
  public IntHolder(int value) {
    this.value = value;
  }
}

Java всегда проходит по значению, и нет глобальных переменных, как в смысле c++. Поэтому, если вы хотите сделать то же самое, что и в C++, вам нужно вернуть новое значение.

таким образом:

public int change(int x) {
    return ++x;
    // or 
    // return x + 1;
}

чтобы проверить это:

int x = 2;

change(x);

System.out.println(x); // returns 2

x = change(x);

System.out.println(x); // returns 3

поэтому нет никакого смысла позволять методу называться change, это более разумно по линии calculateThisInt.


Java передает объекты по значению. Но как Марк Байерс упоминает целое класс является неизменяемым, и вы можете использовать MutableInt из библиотеки Apache Commons. Чтобы описать, как это работает, вы можете реализовать его самостоятельно для своего примера:

public class MyInt() {

    public int i;

    public void setInt(int i) {
        this.i = i;
    }

    public int getInt() { 
        return this.i; 
    }

    public int increment() {
        this.i++;
    }

}

вам нужно изменить свой


оба изменят глобальный x, верно?

Итак, как я могу сделать что-то подобное на java? В частности, я хочу укажите на векторный объект

вопрос несколько расплывчатый, но у меня сложилось впечатление, что вы хотите в конечном итоге глобальные вектор что вы можете держать вещи в?

много способов сделать это, но один из самых простых-это static поле в классе, с public статические методы доступа к нему. (Или просто публичное статическое поле, к которому обращаются напрямую, но это действительно не было бы идиоматичным в Java.)

public class Foo {
    private static List<Integer> globalVector = new Vector<Integer>();

    public static void add(int number){
         globalVector.add(number);
    }

    // ... plus whatever other accessors to the global list that you need 
}

где-нибудь еще в коде:

Foo.add(23); // modifies the global vector

(кстати, вектор устарел, и обычно мы используем ArrayList на его месте. Как говорит Javadoc, он был модифицирован для реализации интерфейса списка, который я также использовал в Примере.)


хотя вы не можете заменить объект, который был передан функции, вы можете изменить его состояние, изменяя поля непосредственно или вызывая методы. Если вам нужно что-то вроде указателя на примитив, оберните его в объект. Чтобы следовать вашему коду, вы можете сделать следующее:

public class IntPointer {
    public int value;
    public IntPointer(int value) {
        this.value = value;
    }
}

потом в другом месте вы могли бы сказать:

public static void change(IntPointer ipoint) {
    ipoint.value++;
}
public static void main(String[] args) {
    IntPointer a = new IntPointer(10);
    change(a);
}

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

public class ABPair {
    private int a = 0;
    private int b = 0;
    public static void changeA() {
        a++;
    }
    public static void changeB() {
        b++;
    }
}

так что в другом месте я могу сказать:

public static void main(String[] args) {
    ABPair ab = new ABPair();
    if (ACondition) {
        ab.changeA();
    }
}

Java поддерживает то, что он называет "ссылки". Ссылки действуют как указатели в языках, подобных C/C++. Они не действуют так же, как" ссылки " работают на этих языках.

основные различия между указателем в C и ссылкой в Java:

вы не можете выполнять арифметику указателей в Java (т. е. вы не можете "добавить" или "вычесть" из ссылки Java, вы можете только разыменовать ее или сравнить с другой). Вы не можете привести его к несовместимому типу: Java строго тип-безопасный, вы не можете "повторно интерпретировать" байты в памяти как какой-то другой объект. Для некоторых применений указателей это не имеет реального эффекта (например, связанные списки работают практически одинаково на обоих языках), для других разница довольно велика (массивы в C-это просто арифметика указателя, в Java они работают совершенно по-разному).

таким образом, ссылки Java можно назвать "ограниченными указателями".