#java #reference #arrays
#java #ссылка #массивы
Вопрос:
Рассмотрим следующие два класса (один из них — метод Main
with main()
):
Класс VO:
public class TheVO {
private String[] theValues = null;
/**
*
*/
public TheVO(String[] theParam) {
this.theValues = theParam;
}
/**
*
* @return
*/
public String[] getValues(){
return this.theValues;
}
@Override
public String toString() {
StringBuffer buf = new StringBuffer("");
if(this.theValues == null){
return buf.toString();
}
for(String read:this.theValues){
buf.append(read);
buf.append(" ");
}
return buf.toString().trim();
}
}
Основной класс:
public class Main {
/**
*
*/
public Main() {
super();
}
/**
* @param args
*/
public static void main(String[] args) {
TheVO theV = new TheVO(new String[]{"Hello","World!!"});
String[] vale = theV.getValues();
vale[0] = "Goodbye";
System.out.println(theV);
}
}
Результат после выполнения:
Прощай, мир!!
Вопрос:
Я знаю, что vale
переменная массива ссылается на ту же переменную, которая анализируется в конструкторе, и если я изменяю один из индексов в массиве, он изменяет то же самое String[]
в VO.
Как мне «исправить» или изменить класс TheVO, чтобы мой результат был?:
Привет, мир!!
Ответ №1:
Вам нужно использовать защитное копирование: скопируйте String[]
в свой конструктор. Это гарантирует, что параметр не будет изменен после того, как он был передан вашему классу VO. Затем скопируйте String[]
в средство получения, чтобы вызывающий средство получения не модифицировал ваш внутренний String[]
. Самый простой способ скопировать arrray — вызвать clone
:
this.theValues = theParam.clone();
Если бы вы использовали коллекции вместо массивов, вы могли бы избавиться от защитной копии в получателе, обернув свою коллекцию с помощью Collections.unmodifiableList()
вместо этого (что является намного более дешевой операцией):
private List<String> theValues;
public List<String> getValues(){
return Collections.unmodifiableList(this.theValues);
}
Однако вам все равно понадобится защитная копия в конструкторе ‘.
Комментарии:
1. Я не хочу прибегать к использованию списка. Все еще хотите вернуть строку[] .
2. Затем вам нужно будет выполнить защитную копию.
Ответ №2:
Вы можете попробовать изменить метод getValues();, чтобы возвращать копию массива tevo.theValues вместо ссылки на исходный массив.
Ответ №3:
Вы можете дублировать (или клонировать) свою строку[] в методе getValues().
Таким образом, создавая новый массив, вы теряете связь между массивами строк.
Ответ №4:
Я бы предложил выполнить копирование внутреннего массива при возврате из TheVO.getValues()
. Если вы работаете на Java 1.6, вы можете использовать Arrays.copyOf()
метод.
public String[] getValues() {
return Arrays.copyOf(theValues, theValues.length);
}
Обратите внимание, что здесь нет необходимости использовать this
для доступа к полю экземпляра.
Ответ №5:
Создайте копию массива в вашем конструкторе VO
Комментарии:
1. Если вы имеете в виду clone(). не работает. Переменной экземпляра присваивается значение clone, и этот clone также задается в основном классе. Похоже, что единственное, что пока работает, — это clone() в методе getValues().
2. Нет — не clone — System.arrayCopy() — не могу вспомнить параметры в верхней части моей головы, но для этого требуется копия исходного массива, а не просто копия ссылки на него.
3.
System.arraycopy()
действительно, является предпочтительным / единственным способом копирования массивов до версии 1.6. Смотрите документацию API по адресу download.oracle.com/javase/6/docs/api/java/lang/System.html для получения дополнительной информации.
Ответ №6:
измените метод getValues(), чтобы клонировать массив…
Что-то вроде этого…
public String[] getValues(){
return this.theValues.clone();
}