Я изменяю объект или копию этого объекта? - PullRequest
2 голосов
/ 22 февраля 2012

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

Вот пример:

for(int i = 0; i < myList.size(); i++)
{
    DataObject myItem = (DataObject)myList.get(i);
    myItem.setString("someKey", "someValue"); 
}

myList - это список объектов DataObject, поэтому я не уверен, какова была цель приведения элемента к объекту DataObject после вызова метода get () в списке. Но мне интересно, как это обрабатывается при компиляции - будет ли приведение создать новый объект, и тогда метод setString () будет вызван для этого нового объекта и не повлияет на объект в списке? Или myItem ссылается на фактический элемент в списке?

Спасибо.

Ответы [ 8 ]

2 голосов
/ 22 февраля 2012

Это по-прежнему ссылка на предмет в списке после каста.Копия не создается.

List возвращает тип класса Object, так что его можно использовать для любого типа Object (так как все классы расширяются Object).Однако для вызова setString вам необходимо привести ссылочный тип к чему-то более конкретному, чтобы компилятор знал, к какому объекту вы вызываете его.

Использование обобщенных значений, например List с вашим списком для указания типов, будет означать, что вам не нужно разыгрывать, но может не подойти, если вы не можете контролировать создание списка или не знаете или не хотитеограничить, какие типы объектов могут быть в нем.

1 голос
/ 22 февраля 2012

Он ссылается на фактический элемент в списке, все, что делает приведение, это говорит компилятору игнорировать объявленный тип , вы знаете, каким будет тип фактического объекта , (Но если вы ошибаетесь, вы получите ClassCastException время выполнения, поэтому при возможности следует избегать приведения. Не вдаваясь в детали, дженерики могут, например, помочь с этим.)

Теперь, такие вещи (изменение элементов коллекции) работают со списками без проблем, но с Set s и для ключей Map s вы должны использовать неизменяемые объекты (в основном объекты, чьи поля не могут изменяться). после вызова конструктора), в противном случае вы можете сделать правильный беспорядок. Вам также следует избегать этого, если ваша коллекция разделена между несколькими потоками.

1 голос
/ 22 февраля 2012

Приведение не создаст новый объект, оно просто скажет компилятору: «Эй, я знаю, что я делаю, и это DataObject».

Не зная типа фактическогоList реализации, мы не можем сказать, является ли то, что вы получаете, одним и тем же объектом.Если вы используете одну из коллекций Java Collections (ArrayList, LinkedList и т. Д.), То это будет тот же экземпляр объекта.Но я мог бы представить реализацию (сделанную мной, конечно!), Которая могла бы возвращать копии, а не базовый экземпляр.

public class MyList<T> implements List<T> {
    private List<T> backingList = new ArrayList<T>();

    //methods to fulfil List interface contract...

    @Override
    public T get(int index) {
        T t = backingList.get(index);
        return makeCopy(t);
    }

    private T makeCopy(T t) {
        //make a copy of t!
    }
}

И именно из-за этого мы не можем сказать (без того, чтобы вы сказали намбазовый тип), если метод get(int) вернет копию или нет.

0 голосов
/ 22 февраля 2012

Вероятно, это тот же объект.

Единственное, что создает объект new, это -гага что? ключевое слово new. Некоторые люди утверждают, что clone() создает новый объект (если он правильно реализован), но - угадайте, что? в функции клона где-то есть ключевое слово new

Теперь я не знаю, с каким myList вы имеете дело, но если предположить, что это часть Стандартных библиотек Java (ArrayList, LinkedList, etc), то вы получите тот же объект.

P.S. Помните, что массивы тоже объекты!

0 голосов
/ 22 февраля 2012

Если myList объявлен как типизированный список, например:

List<DataObject> myList = new ArrayList<DataObject>();

Тогда приведение не требуется.Однако, если это нетипизированный List, его метод get вернет объект типа Object.Это может быть причиной того, что приведение необходимо (не видя объявления, я не могу сказать).

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

0 голосов
/ 22 февраля 2012

myList.get () может быть определен для возврата более общего типа, такого как, например, Object.Вы не можете заставить ссылочную переменную ссылаться на тип более общий, чем он сам.Следовательно, вы должны выполнить приведение -

DataObject myItem = (DataObject) myList.get(i);

Приведение не создаст новый объект.Приведение приведет только к тому, что переменная myItem ссылается на уже существующий объект в списке.Поэтому метод setString () изменяет ваш фактический объект.Поэтому объект в списке также изменяется, потому что это тот же объект.

0 голосов
/ 22 февраля 2012

Приведение не будет создавать новый объект DataObject. Приведения типов обычно не создает новые объекты, , за исключением при преобразовании примитивов в типы-оболочки, или явное или подразумеваемое приведение к String, что приводит к вызову метода toString().

0 голосов
/ 22 февраля 2012

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

Но мне интереснокак это обрабатывается при компиляции - будет ли приведение создать новый объект

Компилятор не будет создавать никаких объектов.Он просто проверяет синтаксис и семантику.При компиляции этой конкретной строки компилятор знает, что ссылка является типом DataObject, но list.get () возвращает тип объекта, что приводит к несовместимым типам.Итак, вам нужно явно бросить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...