Строка [], указывающая на ту же ссылку в объекте VO

#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();
}