Реализовать метод доступ с возвращаемым типом void
Нужно реализовать такой метод без возвращаемого значения. Если нет возвращаемого значения, то мы можем "вытащить" информацию только с помощью передаваемого параметра, как я понимаю. Попытался реализовать это (метод get), не получилось. Не очень понимаю, почему не вышло, ибо String - ссылочный тип, и передается же копия ссылки.
public class Ex3 {
private ArrayList<Integer> array;
private String str;
public Ex3(ArrayList array, String str){
this.array = array;
this.str=str;
}
public void get(String ourString){ //Попытка реализации такого метода
ourString=str;
return;
}
}
Ответы (1 шт):
Причина проблемы:
Чтобы понять причину такого поведения, нужно разобраться в принципах работы с памятью в Java:
- все объекты создаются в куче (
heap), т.е. в общей памяти приложения; - все переменные (в том числе, аргументы методов) хранятся на стэке (
stack), т.е. в памяти определенного потока приложения; - в переменных хранятся лишь ссылки на объекты из кучи (за исключением примитивов);
- при вызове метода в его аргументы просто копируются значения из переменных, которые указываются при его вызове (т.е. по факту, в них копируются адреса ссылок на объекты из кучи, на которые указывают переменные, которые передаются в аргументах вызова метода, т.е. передаются лишь копии ссылок).
Как итог, любое изменение значения (посредством применения оператора присваивания =) аргумента метода никоим образом не скажется на значении переменной из места вызова метода.
Возможно, вот этот пример нагляднее поможет вам разобраться в вышеописанном механизме работы с памятью.
Способы решения проблемы:
Создать объект, обертку над полем, которое вы хотите заполнить в рамках вашего метода, ссылку на экземпляр этого объекта отдать в аргументах вызова метода:
public class Example {
private static class Wrapper {
private String field;
}
public static void main(String[] args) {
Wrapper wrapper = new Wrapper();
fill(wrapper);
System.out.println(wrapper.field);
}
private static void fill(Wrapper wrapper) {
wrapper.field = "some string";
}
}
Опять же, стоит понимать, что в данном случае вы отдаете не null экземпляр объекта обертки над String, т.к. иначе вам просто не у какого объекта из кучи будет заполнять поле.
Точно также вы можете поступить с элементами коллекций (например, ArrayList), т.к. они сами являются обертками над массивом объектов (Object[]), т.е. в каком-то смысле они тоже Wrapper'ы.
Также стоит понимать, что, по факту, класс String сам является оберткой над массивом байт (у него имеется поле private final byte[] value;), предоставляющего методы для работы с ним как с символами в определенной кодировке (например, UTF-8).
Тем не менее, у вас нет возможности изменить содержимое байтового поля у уже существующего экземпляра String (так же, как в примере выше с классом Wrapper) в виду неизменяемости (immutable) экземпляров класса String.
Неизменяемость в рамках экземпляров класса String достигнута за счет того, что:
- байтовое поле инициализируется лишь один раз при создании экземпляра класса (за счет модификатора
final); - прямой доступ к полю отсутствует (за счет модификатора
private, отсутствияset'а, а также возвращении лишь копии массива байт при вызове методаgetBytes).
Заполнять поля чего-то, что итак доступно из метода, например, статического поля класса:
public class Example {
private static String field;
public static void main(String[] args) {
fill();
System.out.println(field);
}
private static void fill() {
field = "some string";
}
}
Не стоит злоупотреблять статикой в Java, такой пример я привел лишь для иллюстрации возможного варианта.
Рекомендации:
Если, все же, вы хотите "заполнять" поля передаваемого объекта, то метод явно лучше назвать отличным от get способом, например, fill, т.к. иначе своим наименованием он будет вводить в заблуждение читающих ваш код людей.