В прошлой теме была рассмотрена передача параметров в метод. Объекты классов, как и данные примитивных типов, также могут передаваться в методы. Однако в данном случае есть одна особенность - при передаче объектов в качестве значения передается копия ссылки на область в памяти, где расположен этот объект.
Сначала рассмотрим более детально, что у нас происходит при передача параметров примитивных типов - числовых типов как int, double и т.д., типа char и boolean:
class Program{
public static void main(String[] args) {
int num = 22;
Calcualtor calc = new Calcualtor();
calc.twice(num);
System.out.printf("num in main (after twice): %d\n", num);
}
}
class Calcualtor{
void twice(int n){
n = n + n;
System.out.printf("n in twice: %d\n", n);
}
}
Здесь в методе main значение переменной num передается в метод calc.twice() параметру n:
calc.twice(num);
В методе calc.twice() значение параметра n (которому передается значение переменной num) увеличивается в два раза:
void twice(int n){
n = n + n;
System.out.printf("n in twice: %d\n", n);
}
И тут возникает главный вопрос: увеличится ли значение переменной num или нет после выполнения метода calc.twice() и почему? Посмотрим на консольный вывод программы:
n in twice: 44 num in main (after twice): 22
По результату программы мы видим, что значение параметра n в методе twice увеличилось в два раза (как и ожидалось), а значение переменной num после выполнения метода twice не изменилось.
При вызове метода calc.twice() параметр n в этом методе получает
копию значения переменной num, то есть число 22:
Когда вызывается метод calc.twice(), в область памяти, которая предназначена для параметра n, копируется значение переменной num - то есть число 22. После этого параметр n и переменная num
никак не связаны - у них разные участки памяти, и изменение значениия одного из них никак не сказывается на другом. Поэтому изменение параметра n никак не влияет на переменную num.
Особенностью переменных других типов является то, что они хранят ссылку на область в памяти, где расположен объект. Рассмотрим небольшой пример:
class Program{
public static void main(String[] args) {
Person bob = new Person();
bob.age = 22;
System.out.printf("bob.age in main (before twice): %d\n", bob.age);
Calcualtor calc = new Calcualtor();
calc.twice(bob);
System.out.printf("bob.age in main (after twice): %d\n", bob.age);
}
}
class Person{
int age;
}
class Calcualtor{
void twice(Person p){
p.age = p.age + p.age;
System.out.printf("p.age in twice: %d\n", p.age);
}
}
Здесь метод twice класса Calculator теперь принимает объект типа Person, у которого есть целочисленное поле age. И в методе twice аналогичным образом это поле увеличивается в два раза.
void twice(Person p){
p.age = p.age + p.age;
System.out.printf("p.age in twice: %d\n", p.age);
}
В методе main определяем переменную bob типа Person и передаем ее значение в метод twice:
Person bob = new Person(); ....................... calc.twice(bob);
Посмотрим на консольный вывод программы:
bob.age in main (before twice): 22 p.age in twice: 44 bob.age in main (after twice): 44
Здесь мы видим, что значение поля age у объекта, на который указывает переменная bob, изменилась. Почему? Так как в метод twice по сути передавается копия ссылки на область памяти, в которой находится объект Person, то переменная bob и параметр p метода twice будут указывать на один и тот же объект в памяти:
Поэтому после выполнения метода у объекта, адрес которого хранит переменная bob и который передается в метод, будет изменено значение age c 22 на 44.
От этого случая следует отличать другой случай:
class Program{
public static void main(String[] args) {
Person bob = new Person();
bob.age = 22;
System.out.printf("bob.age in main (before twice): %d\n", bob.age);
Calcualtor calc = new Calcualtor();
calc.twice(bob);
System.out.printf("bob.age in main (after twice): %d\n", bob.age);
}
}
class Person{
int age;
}
class Calcualtor{
void twice(Person p){
p = new Person(); // создаем новый объект
p.age = 44;
System.out.printf("p.age in twice: %d\n", p.age);
}
}
В метод twice также передается копия ссылки на объект Person. Однако в самом методе мы изменяем не отдельные значения объекта, а пересоздаем объект с помощью конструктора и оператора new. В результате в памяти будет выделено новое место для нового объекта Person, и ссылка на этот объект будет привоена параметру p:
void twice(Person p){
p = new Person(); // создаем новый объект
p.age = 44;
System.out.printf("p.age in twice: %d\n", p.age);
}
То есть после создания нового объекта Person параметр p и переменная bob в методе main будут хранить ссылки на разные объекты. Переменная bob, которая передавалась в метод, продолжит хранить ссылку на старый объект в памяти. Поэтому ее значение не меняется, что мы и увидим по консольному выводу:
bob.age in main (before twice): 22 p.age in twice: 44 bob.age in main (after twice): 22