Помогите разобраться со ссылка в Java

252
15 марта 2017, 17:25

Помогите, пожалуйста разобраться с ссылками в java.

Вот хороший пример:

public class TestClass {
    public static void main(String[] args) {
        int a = 7;
        String s = "asd";
        Person p = new Person("bb1", 6);
        method1(a);
        method2(s);
        method3(p);
        System.out.println(a); //7 - это потому что не было присваивания, верно?
        System.out.println(s); //asd - тут тоже вроде бы понятно
        System.out.println(p); //qwerty - а вот тут - почему только тут содержимое объекта меняется?
    }
    public static void method1(int a) {
        ++a;
        a++;
    }
    public static void method2(String s) {
        s = "bfr";
    }
    public static void method3(Person p) {
        p.setName("qwerty");
    }
}
public class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return name + " " + age;
    }
    public void setName(String name) {
        this.name = name;
    }
}
Answer 1

Все параметры метода передаются в джаве по значению.

1) передавая примитив в метод, значение просто копируется

 public static void method1(int a) {
    ++a;
    a++;
}

т.е. внутри метода создается локальная переменная с именем а, и ее изменение никак не влияет на состояние переменой а в методе main

2) Передавая в метод параметр ссылочного типа, вы передаете копию указателя.

public static void method2(String s) {
    s = "bfr";
}

т.е. s - это какое-то значение 0xA12s, оно указывает на обьект в памяти "asd", и когда вы передаете s в метода, копируется само значение указателя 0xA12s. Т.е. по факту тоже самое что с int. Т.е. от того, что вы измените ссылку s на 0x12abc ничего не изменится, потому что это внутри метода мейн ссылка останется прежней.

3) Когда вы передаете Person, опять же тупо копируются ссылка на этот обьект.

    public static void method3(Person p) {
    p.setName("qwerty");
}

Т.е. внутри main p=0x123 -> (какая-то область в памяти) и
внутри method3 p=0x123 -> (та же область в памяти)

когда вы вызываете сеттер идет разименование ссылки, вызывается метод на том обьекте, ссылку на который вы передали. И меняется его значение в пямяти, т.е.

до   : p=0x123 -> ("bb1", 6) 
после: p=0x123 -> ("qwerty", 6)

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

Рекоммендую включить гугл транслейт и обратиться к похожим вопросам: http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

Answer 2

Если у вас имеется некоторый метод, как, например, этот

public static void method2(String parameter) {
    parameter = "bfr";
}

И вы его вызываете как

String argument = "asd";
method2( argument);

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

public static void method2( /*String parameter*/) {
    String parameter = argument;
    parameter = "bfr";
}

Как видно, в методе меняется значение переменной parameter. Сначала ей присваивается значение переменной argument, а затем новое значение строкового литерала "bfr"

Сама исходная переменная argument не изменилась. Ей ничего не было присвоено.

Что касается этого метода

public static void method3(Person p) {
    p.setName("qwerty");
}

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

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

Answer 3

int - примитивный тип, а вот s уже такой же экземпляр класса String, как и p экземпляр класса Person (именно поэтому String пишется с большой буквы) и в метод передается ссылка на ячейку памяти.

Класс String по сути массив символов.

Но у Stringa есть несколько ньюансов в инициализации. Так например:

s1='string';
s2='string';
s1==s2; // true
READ ALSO
Частота обращений к VK API

Частота обращений к VK API

Обращаюсь к VK API раз в секунду (Threadsleep(1000)), пишу несколько сообщений подряд боту (быстро), и получаю эксепшн: ApiTooManyException: Too many requests per second (6): Too many requests...

800
В чем разница между Comparable и Comparator?

В чем разница между Comparable и Comparator?

Получается, это дублирующие друг друга вещиМожет, есть какие-то реальные различия?

404
Как прочитать файл txt на java

Как прочитать файл txt на java

Есть однострочный txt файл

313
Selenium Drag And Drop не работает на Jenkins

Selenium Drag And Drop не работает на Jenkins

Проблема в следующем: Есть автотест который должен выполнять Drag&Drop элементов в определенном порядкеDrag&Drop реализован в тесте следующим...

327