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

Я изучаю Java в течение нескольких месяцев и теперь начинаю изучать C.

Я немного смущен, у меня создалось впечатление, что передача объекта по ссылке и передача указателя на этот объект-одно и то же: я думал, что разница в том, что в Java все передачи объектов выполняются с указателями автоматически, где, как и в C, нужно фактически разбрызгивать маленькие звездочки и амперсанды здесь и там. Недавно в разговоре меня заверили, что разница!

в чем разница между передачей по ссылке и передав указатель?

10 ответов


Ни Java , ни C имеет pass-by-reference. Они оба строго проходят мимо стоимости.

семантика Pass-by-reference означает, что при изменении значения параметра в методе вызывающий объект увидит это изменение в аргументе.

теперь вы можете подумать: "но это так на Java! Если я изменяю объект во время метода, вызывающий объект видит это изменение."объект не является параметром. параметр просто переменная - и если вы измените значение этой переменной, вызывающего не вижу. Например:

public void foo(Object x)
{
    x = null;
}

public void caller()
{
    Object y = new Object();
    foo(y);
    // y is still not null!
}

если параметр был действительно прошел по ссылке, y после этого будет null. Вместо этого, значение y это просто ссылка, и эта ссылка передается по значению. Это сбивает с толку, потому что слово "Ссылка" в обоих терминах, но это разные вещи.

вы можете посмотреть моя статья о параметре C# проходя чтобы увидеть, что было бы возможно, если Java сделал имеют семантику pass-by-reference, как это делает C#, когда (и только когда) вы используете ref ключевое слово.

вы также можете посмотреть комментарии к мой ответ переполнения стека связанные с темой.


Я думал, что разница в том, что в Java все прохождение объектов выполняется с указателями автоматически, где, как и в C, нужно фактически разбрызгивать маленькие звездочки и амперсанды здесь и там.

концептуальный, это совершенно верно. Если мы педантичны (и это хорошо), мы можем даже сказать, что объекты вообще не передаются на Java. То, что передается, - это только "указатель", который в Java называется ссылкой. Все косвенные действия выполняются автоматически. Так когда вы делаете "objref - >foo "вместо" objref.foo " в C и не может использовать точку, потому что вы работаете с указателем, в Java вы все равно можете использовать точку, потому что она не знает ничего другого для доступа к членам. В C, вы можете передать указатель (и вот это is на самом деле называется указатель) и вы можете передать сам объект, в этом случае копия передается. В C вы получаете доступ к объекту, на который указатель ссылается косвенным образом, используя звезду или" ->". В Java, единственный способ объекты доступны в любом случае, используя точку (objref.член.)

Если мы снова педантичны (теперь снова важнее), ни в Java, ни в C нет "пройти по ссылке". То, что мы передаем в Java, является ссылкой/указателем на объект, и в C мы либо передаем копию объекта (очевидный случай), либо передаем снова только копию указателя на объект. Поэтому в обоих случаях-Java и C - мы передаем адреса объектов. Не говоря уже о примитивных типах java, которые скопировано как на Java, так и на C - хотя вы также можете передать их адрес на C, нет никакой разницы между агрегатным типом (i.E A struct) и "примитивный тип" в C в это связи.


различия тонкие. На уровне сборки, в обоих случаях адрес объекта передается в функцию. Однако в случае указателя параметр является независимым указателем, который может использоваться для изменения целевого объекта (*pch = 'x') или для доступа к другому объекту (pch = "newstr"). В случае ссылки параметр автоматически индиректируется целевому объекту.


Я считаю, что указатель-это переменная, содержащая ссылку. С помощью & вы можете получить направление памяти (ссылку ), а с помощью * вы можете получить доступ к содержимому направления памяти. Я предлагаю книгу язык программирования C .

в отношении


True pass-by-reference означает, что вы можете назначить новое значение ссылке, и это новое значение будет видно в контексте вызова так же, как внутри вызываемого метода.

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


несколько вещей

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

Если вы изучаете C (а не C++), то ссылок нет.

термин "передать по ссылке" в C просто означает, что вы передаете указатель в качестве адреса, в котором будет храниться значение, чтобы функция могла изменить свое значение. В противном случае вы передаете значение, что означает, что копия переменной создается в стеке и изменения не влияют.

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

Если вы использовали C++ (который выглядит как C), то вы можете пройти по ссылке, в этом случае вам не нужно иметь дело с указателями, а изменения переменной в функции фактически изменяют внешнее значение напрямую (за исключением того, что вы не можете заставить его указать на что-то еще).


есть недавняя статья Эрика Липперта об этом. Он программист на компиляторе C#, но все, что он говорит, имеет достаточно общности, чтобы быть распространенным на другие языки GC, такие как Java:

http://blogs.msdn.com/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx

цитата из статьи:

указатели строго "более мощные", чем ссылки; все, что вы можете сделать со ссылками, которые вы можете сделать с указатели. [...]

указатели обычно реализуются как адреса. Адрес-это число, которое является смещением в "массив байтов", который является всем виртуальным адресным пространством процесса. [...]

по всем этим причинам мы не описываем ссылки адресов в спецификации. Спец говорит, что переменная ссылочного типа "хранит ссылку" на объект, и оставляет его совершенно смутные, как это может быть реализовано. Точно так же переменная указателя хранит "адрес" объекта, который опять же остается довольно расплывчатым. Нигде мы не говорим, что ссылки совпадают с адресами.

Итак, в C# ссылка-это какая-то неопределенная вещь, которая позволяет ссылаться на объект. Вы не можете ничего сделать со ссылкой, кроме разыменования ее, и сравнить ее с другой ссылкой для равенства. И в C# указатель идентифицируется как адрес.

в отличие от ссылки, вы можете сделать гораздо больше с помощью указателя там есть адрес. Адресами можно манипулировать математически; вы можете вычитать один из другого, добавить к ним целые числа и так далее. Их юридические операции показывают, что они являются "причудливыми числами", которые индексируются в "массив", который является виртуальным адресным пространством процесса.


те читатели, знакомые с C / C++, вероятно, заметили, что появляются ссылки на объекты быть похожим на указатели. Это подозрение, в сущности, верно. Ссылка на объект подобно указателю памяти. Главное отличие-и ключ к безопасности Java-в том, что вы не можете манипулировать ссылками, как вы можете фактические указатели. Таким образом, вы не можете вызвать ссылка на объект указывает на произвольное расположение памяти или манипулирует им как целым числом.

  • Java не поддерживается & оператор, то как u может получить адрес объекта в java.
  • в java ссылка выполняется объектом, например

MyClass object1 = новый MyClass ();

MyClass object2 = object1;

т. е. вы можете подумать, что object1 и object2 относятся к отдельным и отдельным объектам. Однако это было бы неправильно. Вместо этого после выполнения этого фрагмента object1 и object2 будут ссылаться на один и тот же объект. если вы измените в любом одном эффекте другой.

*вы не можете изменить адрес объекта после инициализации я.Е класса MyClass объект obj =новый класс MyClass(); как ссылка в c++, с object вы можете изменить только значение экземпляра объекта

Примечание: java предоставляет специальную функцию object1 имеет значение null, но object2 по-прежнему указывает на исходный объект.


Я не уверен в java, но в C# или VB.net вы можете пройти по значению или по refrence

пример прохождения мимо refrence

    static void Main(string[] args)
    {
        int x = 1;
        Foo(ref x);
        Console.WriteLine(x.ToString());//this will print 2
    }

    private static void Foo(ref int x)
    {
        x++;
    }

обратите внимание, что x равно 1, но когда вы вызываете метод Foo и передаете x по refrence, когда x увеличивается на единицу в Foo, исходное значение тоже увеличивается