2014-09-18 7 views
6

Я программист на Java. У меня мало знаний о C#. Но из blogs, который я прочитал, Java поддерживает только pass-by-value-of-reference, тогда как в C# по умолчанию используется значение pass-by-value-of-reference, но программист может использовать pass по ссылке, если это необходимо.Как работает метод подкачки на C# на уровне памяти?

Я понял, как работает функция свопинга. Я думаю, что очень важно понять эту концепцию, поскольку она очень важна для концепций программирования.

В C#:

public static void Main() 
{ 
    String ONE = "one"; //1 
    ChangeString(ONE); //2 
    Console.WriteLine(ONE); //3 

    String ONE = "ONE"; //4 
    ChangeString(ref ONE); //5 
    Console.WriteLine(ONE); //6 
} 

private static void ChangeString(String word) 
{ 
    word = "TWO"; 
} 
private static void SeedCounter(ref String word) 
{ 
    word = "TWO"; 
} 
  • Шаг 1: Строка объекта со значением one создается на куче, и адрес его местоположения возвращаемые хранится в переменной ONE. Runtime Environment выделяет кусок памяти в куче и возвращает указатель на начало этого блока памяти. Эта переменная ONE хранится в стеке, который является ссылочным указателем на местоположение фактического объекта в памяти

  • Этап 2: Вызывается метод changeString. Копии указателя (или расположения адреса памяти) назначаются переменному слову. Эта переменная является локальной для метода, которая означает, что когда вызов метода заканчивается, он удаляется из фрейма стека и выходит из области видимости для сбора мусора. В вызове метода переменное слово переназначается, чтобы указать на новое место, где TWO объект находится в памяти. Метод возвращает

  • Шаг 3: Печать на консоли следует напечатать ONE, поскольку то, что было изменено в предыдущем шаге только локальная переменная

  • Шаг 4: Переменный один переназначен, чтобы указать на ячейку памяти, где объект ONE проживает.

  • Этап 5: метод changeString называется. На этот раз передается ссылка на ONE. что это означает, что переменная word локального метода является псевдоним переменной переменной в основной области. Итак, нет копия справок делается. Следовательно, это эквивалентно при мысли, что одна и та же переменная передается вызову метода. Метод переназначает переменную, указывающую на другую ячейку памяти, которая имеет место для хранения TWO. Метод возвращает

  • Шаг 6: Теперь переменная one на внешней сфере, то есть в основном методе изменяется методом вызова, и поэтому он печатает TWO.

В Java, шаг 5 невозможно. То есть вы не можете pass by reference.

Пожалуйста, исправьте, правильно ли описанный выше поток программирования?


Статьи я прочитал, here и here.

+7

Не делайте таких предположений, как * "... создается на куче" *, компилятор может разложить его на кучу , стек или в любом месте .... Это просто подробная информация .... –

+0

@ LB: Спасибо за указание. Я не знал, что компилятор выделяет его. В цитированной выше статье упоминается как куча. поэтому я просто предположил, что это правда –

+0

Вы также можете прочитать эту [правду о типах значений] (http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about -value-types.aspx) –

ответ

3

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

В C# по умолчанию используется ссылка на объект (один уровень косвенности), за исключением типов значений. Передача по ссылке - это, по существу, передача указателя на ссылку на объект, которая является двойной косвенностью.

Ближайшая аналогия C или C++.

C++

void ChangeString(std::string word) 
{ 
    word = "TWO"; 
} 

void SeedCounter(std::string &word) 
{ 
    word = "TWO"; 
} 

C (Игнорирование вопросов сопзЬ и т.д.)

void ChangeString(char * word) 
{ 
    word = strdup("TWO"); 
} 

void SeedCounter(char ** word) 
{ 
    *word = strdup("TWO"); 
} 

Но аналогия Java, вероятно, должен быть класс с членом строки:

public class StringRef 
{ 
    public string val; 
} 

public static void ChangeString(string word) 
{ 
    word = "TWO"; 
} 

public static void SeedCounter(StringRef strRefWord) 
{ 
    strRefWord.val = "TWO"; 
} 

Разработка по запросу.

В C# (или, скорее, в CLR) строковая переменная является указателем, но мы ссылаемся на нее как ссылку на объект. Переменная содержит адрес, который указывает на объект строки, обычно где-то в куче. Сама переменная обычно либо поле класса, где она, вероятно, существует в куче, либо локальная переменная или аргумент, поэтому она существует в стеке или в локальном слоте переменной (также в стеке). Когда вы проходите по ссылке, вы передаете указатель на свою переменную, а не указатель на конечный объект. Ваш параметр «ref» равен A, A указывает на B, который является вашим локальным переменным или полем объекта, а B указывает на C, строковый объект где-то в памяти. Передача с помощью ref передает A, который является указателем на B, и теперь вы можете изменить B.

+0

не могли бы вы уточнить, что это означает в вашем заявлении «Передача по ссылке - это, по сути, передача указателя на ссылку на объект, которая является двойной косвенностью». –

0

Ваше понимание семантики прохождения по ссылке/значению является правильным.

+0

Спасибо Servy! Это толчок для меня –

+1

Это не дает ответа на вопрос. Чтобы критиковать или просить разъяснения у автора, оставьте комментарий ниже их сообщения. – Barranka

+1

@Barranka Как он не отвечает на вопрос? Вопрос был задан, были ли его заявления правильными. Они есть. Это отвечает на вопрос. – Servy