Java. Урок 19. Ссылочные типы

Уроки для начинающих   23 Январь 2013  Автор статьи:  

В данном уроке мы рассмотрим работу с ссылочными типами данных в Java. К ссылочным типам данных относятся массивы, строки и классы. В чем отличие ссылочного типа данных от обычного? Ссылочные типы хранят не значение, а ссылку на него. Таким образом, если вы сравните две переменные ссылочного типа через операцию ==, то вы сравните лишь их адреса:

1
2
3
4
5
String s1 ="ab";
String s2 = new String("ab");
System.out.print("1"=="1");//true
System.out.print(s1==s2);//false
System.out.print(s1=="ab");//true

Пример, находящийся выше должен удивить вас, почему при сравнении двух литералов выдается true, а при сравнении двух строк выдается false? Почему, если при сравнении двух строк выдается false, то почему при сравнении строки с литералом опять выдалось true?
Такое поведение достаточно просто объяснить. Дело в том, что когда вы используете литералы в коде программы, то в памяти компьютера создается некоторая строка со значение литерала, которая подставиться вместо всех вхождений литерала. Таким образом 1==1 вернула истину потому, что мы сравнили строку с самой собой, очевидно, что у строки адрес совпадает сам с собой. Во втором примере, где мы сравнивали строки s1 и s2 вернуло ложь, потому что адреса строк не совпадают. Так как в первой строчке примера я присвоил переменной s1 тот же адрес, что и у литерала ab. Но во второй строке, я заставил создать новую столку со значением «ab». И третья строка вернула true, потому что как говорилось выше все одинаковые литералы лежат по одному адресу в памяти компьютера, а в первой строчке мы присвоили переменной s1 адрес этого литерала.

1
2
3
4
String s1 ="ab";
String s2 = s1 + "c";
System.out.print(s2=="abc");//false
System.out.print(s1==s2);//false

Каждый раз при сложение строк создается новая строка, которая не зависит от своих подстрок. И компьютер не может предугадать результат такого вычисления, поэтому одинаковый литерал «abc» имеет разный адрес.

1
2
3
4
5
6
String s1 ="ab";
String s2 = s1;
s2+="c";
System.out.print(s2.equals("abc"));//true
System.out.print(s1.equals("abc"));//false
System.out.print(s1==s2);//false

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

1
2
3
4
5
6
int[] a = new int[]{1,2,3};
int[] b = a;
b[2] = 100;
for(int i = 0; i < a.length; i++) {
     System.out.print(a[i]);
}

Данный пример выведет 1 2 100, так как массивы указывали на одну и туже ячейку в памяти, то изменения, которые были сделаны в одном отображаются в другом, с таким же успехом мы могли применить любую операцию изменения массива, итог остался бы тем же:

1
2
3
4
b[0]-=100;
b[1] = 100;
b[2]+= 100;
//массив а: -99 100 103

  • Алексей

    нельзя ли писать более грамотно?

    • http://cybern.ru/ lordrp

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

      • Picasso

        Google translate не всегда правильно склоняет слова при переводе. Достаточно просто прочитать урок самому (это 2 минуты) и Вы сами заметите ошибки.

        • http://cybern.ru/ lordrp

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

          • Comment

            вы написали в тексте 1 == 1 вместо «1» == «1»

          • http://cybern.ru/ lordrp

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

  • LuxCore

    Здравствуйте!
    Спасибо Вам огромное за Ваши курсы.
    Прокомментируйте, пожалуйста, следующие примеры.

    String s1 = new String(«ab»);
    String s2 = new String(«ab»);
    System.out.println(«1″==»1″); //true
    System.out.println(s1==s2); //false
    System.out.println(s1==»ab»); //false
    System.out.println(s2==»ab»); //false

    String s1 = «ab»;
    String s2 = «ab»;
    System.out.println(«1″==»1″); //true
    System.out.println(s1==s2); //true
    System.out.println(s1==»ab»); //true
    System.out.println(s2==»ab»); //true

    String s1 = «ab»;
    String s2 = new String(«ab»);
    System.out.println(«1″==»1″); //true
    System.out.println(s1==s2); //false
    System.out.println(s1==»ab»); //true
    System.out.println(s2==»ab»); //false: почему здесь отличается результат от результата строчкой выше?

    Почему new String(«xxx») является излишней записью?

    Спасибо.

    • LuxCore

      Как тут использовать Ваш CodeColorer?

      • http://cybern.ru/ lordrp

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

    • http://cybern.ru/ lordrp

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

      • Елизавета

        Не могли бы Вы разъяснить первый случай из приведенного примера, а именно:
        System.out.println(s1==»ab»); //false
        System.out.println(s2==»ab»); //false
        Правильно ли я понимаю, что у s1, у s2 и у литерала «ab» разные адреса, и поэтому при сравнении результат false?

        и третий случай еще раз, а именно:
        System.out.println(s1==»ab»); //true
        System.out.println(s2==»ab»); //false
        Правильно ли я понимаю, что у s1 и литерала «ab» одинаковый адреса, поэтому результат сравнения true? А у s2 и литерала «ab» разные адреса, поэтому при сравнении результат false?

        Заранее спасибо!

  • ktotam

    Написано: «Дело в том, что когда вы используете литералы в коде программы, то в памяти компьютера создается некоторая строка со значение литерала, которая подставиться вместо всех вхождений литерала.»
    Нужно: «Дело в том, что когда вы используете литералы в коде программы, то в памяти компьютера создается некоторая строка со значением литерала, которая подставится вместо всех вхождений литерала.»
    Написано «Но во второй строке, я заставил создать новую столку со значением «ab». »
    Нужно: «Но во второй строке, я заставил создать новую строку со значением «ab». «

  • soska

    Сосите мой хуййййййййййййййййййййййййййййййййййй

Научиться программировать

  • на Delphi

  • на Java

  • на C++