Как передаются объекты в метод java
Перейти к содержимому

Как передаются объекты в метод java

  • автор:

Java: передача параметров по значению или по ссылке

Простое объяснение принципов передачи параметров в Java.

Многие программисты часто путают, какие параметры в Java передаются по значению, а какие по ссылке. Давайте визуализируем этот процесс, и тогда вы увидите насколько все просто.

Данные передаются между методами через параметры. Есть два способа передачи параметров:

  1. Передача по значению (by value). Значения фактических параметров копируются. Вызываемый метод создает свою копию значений аргументов и затем ее использует. Поскольку работа ведется с копией, на исходный параметр это никак не влияет.
  2. Передача по ссылке (by reference). Параметры передаются как ссылка (адрес) на исходную переменную. Вызываемый метод не создает свою копию, а ссылается на исходное значение. Следовательно, изменения, сделанные в вызываемом методе, также будут отражены в исходном значении.

В Java переменные хранятся следующим образом:

  1. Локальные переменные, такие как примитивы и ссылки на объекты, создаются в стеке.
  2. Объекты — в куче (heap).

Теперь вернемся к основному вопросу: переменные передаются по значению или по ссылке?

Java всегда передает параметры по значению

Чтобы разобраться с этим, давайте посмотрим на пример.

Пример передачи примитивов по значению

Поскольку Java передает параметры по значению, метод processData работает с копией данных. Следовательно, в исходных данных (в методе main ) не произошло никаких изменений.

Теперь рассмотрим другой пример:

Передача объекта

Что здесь происходит? Если Java передает параметры по значению, то почему был изменен исходный список? Похоже, что Java все-таки передает параметры не по значению? Нет, неправильно. Повторяйте за мной: «Java всегда передает параметры по значению».

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

Память стека (stack) и кучи (heap)

В программе, приведенной выше, список fruits передается методу processData . Переменная fruitRef — это копия параметра fruit . И fruits и fruitsRef размещаются в стеке. Это две разные ссылки. Но самое интересное заключается в том, что они указывают на один и тот же объект в куче. То есть, любое изменение, которое вы вносите с помощью любой из этих ссылок, влияет на объект.

Давайте посмотрим на еще один пример:

Передача объекта по ссылкеПамять стека (stack) и кучи (heap)

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

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

Вышеприведенная концепция очень важна для правильного решения ваших задач.

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

Удаление узла в связанном списке

class Node < int data; Node next; Node(int d)< data = d; next = null; >> class LinkedList < public static Node push(Node head, int data) < Node newNode = new Node(data); newNode.next = head; head = newNode; return head; >public static void deleteNode(Node head, int position) < // List is empty if (head == null)< return; >// If position is 1st, removing head node if (position == 1) < head = head.next; return; >Node prevNode = head; int i = 2; while (prevNode != null && i != position) < prevNode = prevNode.next; i++; >// When position is more than number of node if (prevNode == null || prevNode.next == null) < return; >prevNode.next = prevNode.next.next; > public static void printList(Node head) < Node currNode = head; while (currNode != null) < System.out.print(currNode.data + " "); currNode = currNode.next; >> public static void main(String[] args) < Node head = null; head = push(head, 5); head = push(head, 4); head = push(head, 3); head = push(head, 2); head = push(head, 1); System.out.println("Created Linked list is: "); printList(head); // Delete node at position 2 deleteNode(head, 2); System.out.println("\nLinked List after Deletion at position 2: "); printList(head); >> 

Это решение работает во всех случаях, кроме одного — когда вы удаляете первый узел ( Position = 1 ). Основываясь на ранее описанной концепции, видите ли вы в чем здесь проблема? Возможно, поможет следующая диаграмма.

Удаление первого узла односвязного списка

Для исправления алгоритма необходимо сделать следующее:

public static Node deleteNode(Node head, int position) < // List is empty if (head == null)< return head; >// If position is 1st, removing head node if (position == 1) < head = head.next; return head; >Node prevNode = head; int i = 2; while (prevNode != null && i != position) < prevNode = prevNode.next; i++; >// When position is more than number of node if (prevNode == null || prevNode.next == null) < return head; >prevNode.next = prevNode.next.next; return head; > public static void main(String[] args) < Node head = null; head = push(head, 5); head = push(head, 4); head = push(head, 3); head = push(head, 2); head = push(head, 1); System.out.println("Created Linked list is: "); printList(head); // Delete node at position 2 head = deleteNode(head, 2); System.out.println("\nLinked List after Deletion at position 2: "); printList(head); >//Rest of the code remains same 

В этой статье мы обсудили одну небольшую, но важную концепцию Java: передачу параметров.

Перевод статьи подготовлен в преддверии старта курса «Подготовка к сертификации Oracle Java Programmer (OCAJP)».

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

ЗАПИСАТЬСЯ НА ВЕБИНАР

  • Блог компании OTUS
  • Программирование
  • Java

Использование объектов в качестве параметров

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

// Методам можно передавать объекты. class Test < int a, b;
Test(int i, int j) a = i;
b = j;
>
// возврат значения true, если параметр о равен вызывающему объекту
boolean equals(Test о) if(о.а == а && o.b == b) return true;
else return false;
class PassOb public static void main(String args[]) Test obi = new Test(100, 22);
Test ob2 = new Test(100, 22);
Test ob3 = new Test(-1, -lb-System, out .println («obi == ob2: » + obi.equals(ob2) ) ;
System.out.println(«obi == ob3 : » + obi.equals(ob3));
>
>

Эта программа создает следующий вывод:

obi == ob2: true
obi == оЬЗ: false

Как видите, метод equals () внутри метода Test проверяет равенство двух объектов и возвращает результат этой проверки. То есть он сравнивает вызывающий объект с тем, который был ему передан. Если они содержат одинаковые значения, метод возвращает значение true. В противном случае он возвращает значение false. Обратите внимание, что параметр о в методе equals () указывает Test в качестве типа. Хотя Test — тип класса, созданный программой, он используется совершенно так же, как встроенные типы Java.

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

//В этой версии Box допускает инициализацию одного объекта другим.
class Box double width;
double height;
double depth;
// Обратите внимание на этот конструктор. Он использует объект типа Во:
Box(Box ob) < // передача объекта конструктору
width = ob.width;
height = ob.height;
depth = ob.depth;
>
// конструктор, используемый при указании всех измерений
Box(double w, double h, double d) width = w;
height = h;
depth = d;
>
// конструктор, используемый, если ни одно из изменений не указано
Box () width = -1; // значение -1 используется для указания
height = -1; //не инициализированного
depth = -1; // параллелепипеда
>
// конструктор, используемый при создании куба
Box(double len) width = height = depth = len;
>
// вычисление и возврат объема
double volume () <
return width * height * depth;
>
>
class 0verloadCons2 public static void main(String args[]) // создание параллелепипедов с применением различных конструкторов
Box myboxl = new Box(10, 20, 15);
Box mybox2 = new Box() ;
Box mycube = new Box (7) ;
Box myclone = new Box(myboxl) ; // создание копии объекта
myboxl double vol;
// получение объема первого параллелепипеда
vol = myboxl.volume () ;
System.out.println(«Объем myboxl равен » + vol);
// получение объема второго параллелепипеда
vol = mybox2.volume();
System.out.println(«Объем mybox2 равен » + vol);
// получение объема куба
vol = mycube.volume О ;
System.out.println(«Объем куба равен » + vol);
// получение объема клона
vol = myclone.volume О;
System.out.println(«Объем клона равен » + vol);
>
>

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

Передача параметров в метод Java

Возможно я что — то не так понимаю. Но по моей логике переменная переданная в метод и дальнейшие модификации с ней должны остаться в это методе, и исчезнуть вместе с методом. Но в итоге я вижу в main измененный массив mas. Почему так происходит. Потому что в таком случае пропадает надобность в return. В Java давно, а тут такое. Видать что — то серьезное я забыл.

testA 100 testA 100 testA 100 testA 4 testA 5 test 100 test 100 test 100 test 4 test 5 Main 100 Main 100 Main 100 Main 4 Main 5 

Отслеживать
51.6k 201 201 золотой знак 65 65 серебряных знаков 246 246 бронзовых знаков
задан 12 янв 2018 в 13:07
user239760 user239760

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

12 янв 2018 в 13:09

Посмотрите главу «Подробное рассмотрение особенностей передачи аргументов» в полном руководстве по Java авторства Герберта Шилдта.

12 янв 2018 в 13:41

@post_zeew, У вас в доме кран протекает. Что делать? Идти в библиотеку, брать книгу и сидеть читать, как стать слесарем или позвонить сантехникам и ждать минут 30. Пока всех соседей не затопит. Было бы правильнее вам в начале помочь решить проблему, а после уже давать советы по книгам. Но в общем спасибо за книгу. А то ведь так любой может зайти в SO и писать в комментах. Чувак иди в Google там все есть

– user239760
12 янв 2018 в 13:58

Я ссылаюсь на конкретную главу книги, там даже не глава, а несколько абзацев. Книга в свободном доступе в электронном виде. В данном случае я указал именно на главу книги, так как в интернете на эту тему очень много принципиально неверной информации. В книге же все подробно расписано. И к слову: проблема большинства начинающих программистов заключается в том, что они не читают книги, в которых описываются фундаментальные вещи и не зная самых азов начинают писать что-то относительно сложное.

12 янв 2018 в 14:14
@post_zeew, или же они просто забывают что — то.
– user239760
12 янв 2018 в 15:30

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

@AlexChermenin замудрено объяснили. Объекты передаются по ссылке, примитивы по значению. Массивы примитивов — это объекты, поэтому передаются также по ссылке.

Обновлено: под передачей по ссылке я имею ввиду, что объект таки передается по значению. Но в значении содержится ссылка на объект, а не копия объекта.

int number = 0; void update(int num) < num++; System.out.println(num); // 1 >update(number); System.out.println(number); // 0 
int[] numbers = new int[]; void update(int[] nums) < for(int i=0; i < nums.length; i++) < nums[i] = 5-i; >> update(numbers); /** * Ага, а тут кстати вызывается toString(), чего нет у примитивов */ System.out.println(numbers); //

Отслеживать
ответ дан 12 янв 2018 в 13:23
18.1k 25 25 серебряных знаков 49 49 бронзовых знаков
Всё передаётся по значению, только для объектов ссылка и есть значение 🙂
12 янв 2018 в 13:25

У массивов тоже есть указатели, так как они выделают место в памяти. Так получается? А не имеет значение что это метод static или обычный ?

– user239760
12 янв 2018 в 13:34
@AlexChermenin под ссылкой вы имете ввиду hashCode?
– user239760
12 янв 2018 в 13:36

Массив — это объект. Изменяя элемент объекта, вы изменяете его по ссылке. Если же вы сделаете так: for(int num : nums) < num = 5; >то ничего не прокатит, потому что вы получите примитивный элемент массива, который получили уже как значение.

12 янв 2018 в 13:37
Не путайте, пожалуйста, людей. В Java все параметры передается по значению.
12 янв 2018 в 13:39

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

Представьте себе ссылку, как «пульт управления переменной». Вы передаете в метод только «пульт управления» при передаче по ссылке. При выходе из метода уничтожается только «пульт управления», то есть ссылка. При передаче примитивного типа, происходит передача значения. То есть копируется значение переменной. А при выходе из метода исчезает эта копия. Исчезает значение переменной — копии.

Отслеживать
ответ дан 13 янв 2018 в 6:35
Vyacheslav Mishchenko Vyacheslav Mishchenko
537 1 1 золотой знак 5 5 серебряных знаков 13 13 бронзовых знаков

А как тогда создать клон объекта, чтобы у него был свой указатель, но значения все передались другому объекту. Короче у объекта есть 10 переменных. Чтобы через равно не передавать их все. Можно как — то одной строкой передать их все другому новому объекту? И как сделать это

– user239760
13 янв 2018 в 6:57

1. Переопределение метода clone() и реализация интерфейса Cloneable(); 2. Использование конструктора копирования; 3. Использовать для клонирования механизм сериализации Ссылка >>> habrahabr.ru/post/246993

Передача и возврат объектов в методы Java

Как мы знаем, это основная концепция, что в Java всегда передается по значению, а не по ссылке. Так что в этом посте мы сосредоточимся на том, как эта концепция проверяется в случае передачи примитива и передачи ссылки в метод.

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

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

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

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

Разберем пример передачи и возврата объектов в Java –

Пример

public class PassByValue < static int k =10; static void passPrimitive(int j) < System.out.println("the value of passed primitive is " + j); j = j + 1; >static void passReference(EmployeeTest emp) < EmployeeTest reference = emp; System.out.println("the value of name property of our object is "+ emp.getName()); reference.setName("Bond"); >public static void main(String[] args) < EmployeeTest ref = new EmployeeTest(); ref.setName("James"); passPrimitive(k); System.out.println("Value of primitive after get passed to method is "+ k); passReference(ref); System.out.println("Value of property of object after reference get passed to method is "+ ref.getName()); >> class EmployeeTest < String name; public String getName() < return name; >public void setName(String name) < this.name = name; >>

Итог

the value of passed primitive is 10 Value of primitive after get passed to method is 10 the value of name property of our object is James Value of property of object after reference get passed to method is Bond

Средняя оценка 4 / 5. Количество голосов: 4

Спасибо, помогите другим — напишите комментарий, добавьте информации к статье.

Или поделись статьей

Видим, что вы не нашли ответ на свой вопрос.

Помогите улучшить статью.

Напишите комментарий, что можно добавить к статье, какой информации не хватает.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *