Кто-то может объяснить мне, каково обоснование позади передачи “значением” а не “ссылкой” в Java?

Это должно сработать для вас.

Private Sub Worksheet_Change(ByVal Target As Range)

Dim Scan As Variant

Scan = Trim(Target.Value)
If Len(Scan) And Target.Column > 2 Then
    If Left(Scan, 1) = "$" Then
        Scan = Mid(Scan, 2)
        With Application
            .ScreenUpdating = False
            .EnableEvents = False
        End With
        If Target.Column > 3 Then
            Target.ClearContents
            Set Target = Cells(Target.Row + 1, 3)
        End If
        Target.Value = Scan
        With Application
            .EnableEvents = True
            .ScreenUpdating = True
        End With
    End If

    Target.Offset(0, Sgn(Val(Scan))).Select
End If

End Sub

Код был расширен, чтобы включить новые требования в соответствии с вашим комментарием.

8
задан WW. 5 February 2009 в 04:23
поделиться

15 ответов

Эта напыщенная речь объясняет это лучше, чем я мог когда-либо даже пытаться:

В Java примитивы передаются значением. Однако Объекты не передаются ссылкой. Корректным оператором были бы Ссылки на объект, передаются значением.

11
ответ дан 5 December 2019 в 05:19
поделиться

Пойдите делают действительно большое учебное руководство на веб-сайте солнц.

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

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

-2
ответ дан 5 December 2019 в 05:19
поделиться

Это вызвано тем, что внутри "thisDoesntWork", Вы эффективно уничтожаете локальное значение нечто. Если Вы хотите передать ссылкой таким образом, может всегда инкапсулировать Строку в другом объекте, говорить в массиве.

class Test {

    public static void main(String[] args) {
        String [] fooArray = new String[1];
        fooArray[0] = new String("foo");

        System.out.println("main: " + fooArray[0]);
        thisWorks(fooArray);
        System.out.println("main: " + fooArray[0]);
    }

    public static void thisWorks(String [] foo){
        System.out.println("thisWorks: " + foo[0]);
        foo[0] = "howdy";
        System.out.println("thisWorks: " + foo[0]);
    }
}

Результаты в следующем выводе:

main: foo
thisWorks: foo
thisWorks: howdy
main: howdy
0
ответ дан 5 December 2019 в 05:19
поделиться

Введенные аргументы ссылки передаются как ссылки на сами объекты (не ссылки на другие переменные, которые относятся к объектам). Можно назвать методы на объекте, который был передан. Однако в Вашем примере кода:

public static void thisDoesntWork(String foo){
    foo = "howdy";
}

Вы только храните ссылку на строку "howdy" в переменной, которая локальна для метода. Та локальная переменная (foo) был инициализирован к значению вызывающей стороны foo когда метод назвали, но не имеет никакой ссылки на саму переменную вызывающей стороны. После инициализации:

caller     data     method
------    ------    ------
(foo) -->   ""   <-- (foo)

После присвоения в Вашем методе:

caller     data     method
------    ------    ------
(foo) -->   ""
          "hello" <-- (foo)

Вы имеете, другой выходит там: String экземпляры неизменны (дизайном, для безопасности), таким образом, Вы не можете изменить ее значение.

Если Вы действительно хотите, чтобы Ваш метод обеспечил начальное значение для Вашей строки (или когда-либо в ее жизни, в этом отношении), то имейте свой возврат метода a String значение, которое Вы присваиваете переменной вызывающей стороны при вызове. Что-то вроде этого, например:

String foo = thisWorks();
System.out.println(foo);//this prints the value assigned to foo in initialization 

public static String thisWorks(){
    return "howdy";
}
-1
ответ дан 5 December 2019 в 05:19
поделиться

При размышлении об объекте как просто, поля в объекте затем возражают, передаются ссылкой в Java, потому что метод может изменить поля параметра, и вызывающая сторона может наблюдать модификацию. Однако, если Вы также думаете об объекте, поскольку это - идентификационные данные, затем возражает, передаются значением, потому что метод не может изменить идентификационные данные параметра способом, который может наблюдать вызывающая сторона. Таким образом, я сказал бы, что Java является передачей значением.

0
ответ дан 5 December 2019 в 05:19
поделиться

@Axelle

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

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

0
ответ дан 5 December 2019 в 05:19
поделиться

Dave, необходимо простить мне (хорошо, я предполагаю, что Вы "не имеете к", но я быть бы, Вы сделали), но то объяснение не чрезмерно убедительно. Усиления безопасности довольно минимальны начиная с любого, кто должен измениться, значение строки найдет способ сделать это с некоторым ужасным обходным решением. И скорость?! Вы сами (вполне правильно) утверждаете, что целый бизнес с + является чрезвычайно дорогим.

Остальная часть Вас парни, поймите, что я ДОБИРАЮСЬ, как она работает, я спрашиваю, ПОЧЕМУ она прокладывает себе путь..., прекратите объяснять различие между методологиями.

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

0
ответ дан 5 December 2019 в 05:19
поделиться

Это - потому что, это создает локальную переменную в методе. то, что было бы простым способом (который я вполне уверен, работало бы), будет:

String foo = new String();    

thisDoesntWork(foo);    
System.out.println(foo); //this prints nothing

public static void thisDoesntWork(String foo) {    
   this.foo = foo; //this makes the local variable go to the main variable    
   foo = "howdy";    
}
0
ответ дан 5 December 2019 в 05:19
поделиться

Если мы сделали бы грубый C и ассемблерную аналогию:

void Main()
{ 
     // stack memory address of message is 0x8001.  memory address of Hello is 0x0001.  
     string message = "Hello"; 
     // assembly equivalent of: message = "Hello";
     // [0x8001] = 0x0001

     // message's stack memory address
     printf("%d", &message); // 0x8001

     printf("%d", message); // memory pointed to of message(0x8001): 0x0001
     PassStringByValue(message); // pass the pointer pointed to of message.  0x0001, not 0x8001
     printf("%d", message); // memory pointed to of message(0x8001): 0x0001.  still the same

     // message's stack memory address doesn't change
     printf("%d", &message); // 0x8001
}

void PassStringByValue(string foo)
{
    printf("%d", &foo); // &foo contains foo's *stack* address (0x4001)

    // foo(0x4001) contains the memory pointed to of message, 0x0001
    printf("%d", foo);  // 0x0001
    // World is in memory address 0x0002
    foo = "World";  // on foo's memory address (0x4001), change the memory it pointed to, 0x0002
    // assembly equivalent of: foo = "World":
    // [0x4001] = 0x0002

    // print the new memory pointed by foo
    printf("%d", foo); // 0x0002

    // Conclusion: Not in any way 0x8001 was involved in this function.  Hence you cannot change the Main's message value.
    // foo = "World"  is same as [0x4001] = 0x0002

}

void Main()
{
     // stack memory address of message is 0x8001.  memory address of Hello is 0x0001.  
     string message = "Hello"; 
     // assembly equivalent of: message = "Hello";
     // [0x8001] = 0x0001

     // message's stack memory address
     printf("%d", &message); // 0x8001

     printf("%d", message); // memory pointed to of message(0x8001): 0x0001
     PassStringByRef(ref message); // pass the stack memory address of message.  0x8001, not 0x0001
     printf("%d", message); // memory pointed to of message(0x8001): 0x0002. was changed

     // message's stack memory address doesn't change
     printf("%d", &message); // 0x8001
}


void PassStringByRef(ref string foo)
{
    printf("%d", &foo); // &foo contains foo's *stack* address (0x4001)

    // foo(0x4001) contains the address of message(0x8001)
    printf("%d", foo);  // 0x8001
    // World is in memory address 0x0002
    foo = "World"; // on message's memory address (0x8001), change the memory it pointed to, 0x0002
    // assembly equivalent of: foo = "World":
    // [0x8001] = 0x0002;


    // print the new memory pointed to of message
    printf("%d", foo); // 0x0002

    // Conclusion: 0x8001 was involved in this function.  Hence you can change the Main's message value.
    // foo = "World"  is same as [0x8001] = 0x0002

}

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

Они сделали бы, Вы разработать целочисленную программу подкачки с помощью объектов, чем их оказываете поддержку первого класса для передачи ссылкой, то же для делегата (Гусенок чувствует себя неприглядным с указателем для функционирования, он переполнил бы ту функциональность к объектам), и перечисление.

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

1
ответ дан 5 December 2019 в 05:19
поделиться

Проблема - Вы, инстанцируют ссылочного типа Java. Затем Вы передаете тот ссылочный тип статическому методу и повторно присваиваете его локально ограниченной по объему переменной.

Это не имеет никакого отношения к неизменности. Точно то же самое произошло бы для изменяемого ссылочного типа.

2
ответ дан 5 December 2019 в 05:19
поделиться

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

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

Некоторые преимущества включают: - никакая потребность сделать защитные копии. - Ориентированный на многопотоковое исполнение - никакая потребность волноваться о блокировке на всякий случай кто-то еще хочет изменить объект.

3
ответ дан 5 December 2019 в 05:19
поделиться

Ваш вопрос, как спросили действительно не имеет отношение к передаче значением, передающим ссылкой или тем, что строки неизменны (поскольку другие заявили).

В методе Вы на самом деле создаете локальную переменную (я назову тот один "localFoo"), который указывает на ту же ссылку как Ваша исходная переменная ("originalFoo").

Когда Вы присваиваетесь "привет" к localFoo, Вы не изменяетесь, где originalFoo указывает.

Если Вы сделали что-то как:

String a = "";
String b = a;
String b = "howdy"?

Ожидайте:

System.out.print(a)

распечатать "привет"? Это распечатывает "".

Вы не можете изменить то, на что указывает originalFoo путем изменения того, на что указывает localFoo. Можно изменить объект, что обе точки к (если это не было неизменно). Например,

List foo = new ArrayList();
System.out.println(foo.size());//this prints 0

thisDoesntWork(foo);
System.out.println(foo.size());//this prints 1

public static void thisDoesntWork(List foo){   
    foo.add(new Object);
}
4
ответ дан 5 December 2019 в 05:19
поделиться

Вы уверены, что это печатает пустой указатель? Я думаю, что это будет просто пробел как тогда, когда Вы инициализировали переменную нечто, Вы обеспечили пустую строку.

Присвоение нечто в thisDoesntWork методе не изменяет ссылку переменной нечто, определенной в классе, таким образом, нечто в System.out.println (нечто) все еще укажет на старый объект пустой строки.

0
ответ дан 5 December 2019 в 05:19
поделиться

При передаче "нечто" Вы передаете ссылку на "нечто" как значение в ThisDoesntWork (). Это означает, когда Вы делаете уроки к "нечто" в Вашем методе, простую установку локальной переменной (нечто) ссылка, чтобы быть ссылкой на новую строку.

Другая вещь иметь в виду при размышлении о том, как строки ведут себя в Java, состоит в том, что строки неизменны. Это работает тот же путь в C#, и на некоторых серьезных основаниях:

  • Безопасность: Никто не может запихнуть данные в Вашу строку и вызвать ошибку переполнения буфера, если никто не может изменить его!
  • Скорость: Если можно быть уверены, что строки неизменны, Вы знаете, что его размер всегда является тем же, и Вы никогда не должны делать перемещения структуры данных в памяти при управлении им. Вы (разработчик языка) также не должны волноваться о реализации Строки как медленный связанный список, также. Это имеет свои плюсы и минусы, все же. При добавлении строк просто с помощью + оператор может быть дорог мудрый памятью, и необходимо будет использовать объект StringBuilder сделать это высокоэффективным, эффективным памятью способом.

Теперь на Ваш больший вопрос. Почему объекты передаются этот путь? Ну, если бы Java передал Вашу строку как, что Вы традиционно назвали бы "значением", то это должно будет на самом деле скопировать всю строку прежде, чем передать его Вашей функции. Это довольно медленно. Если бы это передало строку ссылкой, и позвольте Вам измениться, это (как C делает), у Вас были бы проблемы, которые я просто перечислил.

9
ответ дан 5 December 2019 в 05:19
поделиться

Так как мой исходный ответ был, "Почему это произошло" и не, "Почему язык был разработан так, это произошло", я дам это, другие идут.

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

String a = "hello";
String b = a;
String b = "howdy"

System.out.print(a) //prints hello

Чтобы заставить последний оператор печатать "привет", b должен указать на ту же "дыру" в памяти что точки к (указатель). Это - то, что Вы хотите, когда Вы хотите передачу ссылкой. Существует несколько причин, Java решил не пойти это направление:

  • Указатели Смущают разработчиков Java, которую попробовали для удаления некоторых более запутывающих вещей о других языках. Указатели являются одной из самых недооцененных и неправильно используемых конструкций C/C++ наряду с перегрузкой оператора.

  • Указатели являются причиной Указателей Угроз безопасности много проблем безопасности при неправильном использовании. Вредоносная программа присваивает что-то той части памяти, затем что Вы думали, был Ваш объект, на самом деле чужой. (Java уже избавился от самой большой проблемы безопасности, переполнения буфера, с проверенными массивами),

  • Утечка абстракции, Когда Вы начинаете иметь дело с, "Что находится в памяти и где" точно, Ваша абстракция становится меньшим количеством абстракции. В то время как утечка абстракции почти наверняка вползает на язык, разработчики не хотели печь ее в непосредственно.

  • Объекты - Все Вы Забота О В Java, все - объект, не место, которое занимает объект. Добавление указателей сделало бы пространство, объект занимает importantant, хотя.......

Вы могли эмулировать то, что Вы хотите путем создания объекта "Дыры". Вы могли даже использовать дженерики для создания этого безопасным с точки зрения типов. Например:

public class Hole<T> {
   private T objectInHole;

   public void putInHole(T object) {
      this.objectInHole = object;
   }
   public T getOutOfHole() {
      return objectInHole;
   }

   public String toString() {
      return objectInHole.toString();
   }
   .....equals, hashCode, etc.
}


Hole<String> foo = new Hole<String)();
foo.putInHole(new String());
System.out.println(foo); //this prints nothing
thisWorks(foo);
System.out.println(foo);//this prints howdy

public static void thisWorks(Hole<String> foo){
   foo.putInHole("howdy");
}
5
ответ дан 5 December 2019 в 05:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: