Почему эта одна переменная влияет? - PullRequest
1 голос
/ 24 декабря 2011

Это мой первый вопрос в StackOverflow. Это код вопроса:

public class ListStuff {
  public static void main(String [] args) {

    String[] randomNames = {"Herbie", "Jaco", "Pat", "Michael"};        
    String[] reversedNames = revertNames(randomNames);

    for (int i = 0; i < reversedNames.length; i++) {
        System.out.println(reversedNames[i]);
    }   
  }

  public static String[] revertNames(String[] s) {

    for (int i = 0; i < s.length / 2; i++) {
       String tmp = s[s.length - 1 - i];
       s[s.length - 1 - i] = s[i];
       s[i] = tmp;
    }  

  return s;
  }
}

Этот код работает нормально, а переменная reversedNames печатается как обращенная; нареканий нет. Моя главная проблема, однако, заключается в том, что когда я делаю String[] reversedNames = revertNames(randomNames);, переменная randomNames также возвращается. Я ни в коем случае не изменяю переменную randomNames с помощью randomNames = blabla;, поэтому не могу понять, почему эта переменная продолжает превращаться в обращенную версию, даже если я передаю ее только в качестве аргумента.

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

Ответы [ 5 ]

7 голосов
/ 24 декабря 2011

Массивы в Java являются ссылочными типами.Это означает, что когда вы передаете свой массив методу revertNames, любые изменения внутри этого метода также будут видны снаружи.Поскольку вы изменяете параметр массива s внутри revertNames с помощью этого кода:

String tmp = s[s.length - 1 - i];
s[s.length - 1 - i] = s[i];
s[i] = tmp;

исходный массив randomNames, который был передан вместо s, также изменяется в процессе.1009 *

3 голосов
/ 24 декабря 2011

Это потому, что вы передаете массив по ссылке, а не по значению. По сути, это означает, что массив reversedNames по-прежнему указывает на массив randomNames, поэтому изменение одного изменит другой.

Вот диаграмма переменных:

Первоначально:

randomNames

Когда мы вводим функцию revertNames:

randomNames <-------- s

Массив s по-прежнему указывает на массив randomNames! Таким образом, когда мы меняем s, мы также меняем randomNames.

Как мы покидаем функцию:

randomNames <--------- s <--------- reversedNames

Таким образом, reversedNames указывает на randomNames.

После завершения вызова функции:

randomNames <--------- reversedNames

Хотя массив s исчез, reversedNames по-прежнему указывает на randomNames.

Чтобы устранить проблему, создайте временную переменную внутри функции revertNames:

public static String[] revertNames(String[] oldarray) {
    // Create temporary array to avoid affecting original array
    String[] s = oldarray.clone();
    ...
1 голос
/ 24 декабря 2011

В теле revertNames у вас есть переменная s, это ссылка на объект, который является массивом.Фактическим массивом является массив randomNames.Таким образом, вы действительно меняете значения в исходном массиве.

Если вы используете Arrays.copy (), вы можете получить независимый массив для работы - копия будет указывать на те же строки, что и исходный массив, но какСтруны неизменны, это безопасно.

0 голосов
/ 24 декабря 2011

Массивы в Java являются ссылочными типами, т. Е. Если вы объявите

String[] randomNames;

, вы объявите локальную переменную, которая содержит ссылку на объект, представляющий собой массив строк.

оператор

String[] otherNames = randomNames;

скопирует содержимое переменной randomNames в переменную otherNames, но содержимое является просто ссылкой.То есть этот оператор заставляет и другие имена, и случайные имена ссылаться на один и тот же объект массива.

То же самое происходит, когда вы передаете String[] в качестве параметра метода.То есть локальная переменная s в revertNames и локальная переменная randomNames в main будут содержать идентичные ссылки, т.е. ссылаться на один и тот же объект массива.То есть состояние этого объекта массива будет видимым, хотя и s, и randomNames.

Строго говоря, это не имеет никакого отношения к области видимости, поскольку переменная randomNames не изменена (т.е.он все еще указывает на тот же массив).Что модифицируется, так это объект, к которому он относится.

0 голосов
/ 24 декабря 2011

Вы можете использовать: StringBuffer: reverse ()

что-то в этом роде:

public class t {
  public static void main(String [] args) {

    String[] randomNames = {"Herbie", "Jaco", "Pat", "Michael"};        
    StringBuffer rev;
    for (int i = 0; i < randomNames.length; i++) 
    {
       rev=new StringBuffer(randomNames[i]);
        System.out.println(rev.reverse().toString());
    }   
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...