2013-12-24 3 views
1

Я знаю, эта тема очень избита, но ...Pass по значению или ссылки

Я программирования приложения для андроид в Java, но я из C++, где вопрос о стоимости или ссылки очень явный. Проблема заключается в том:

Изначально у меня есть класс с именем Item, который имеет переменную общественного Int ID.

В классе под названием ListingItem, у меня есть список из статического списка с два вещи добавила к нему, каждому присвоил свою переменной ID величиной . В этом классе есть также функция public static List getList(), которая возвращает Список, в частности, Список этого класса.

В другом классе, называется Фрагмент, у меня есть Список ITEMLIST и функция частный Список GetList(), который возвращаетСписок.

GetList() класса фрагмента делает следующее:

private List <Item> getList() 
{ 
    List<Item> list = ListingItem.getList() // copy list from ListingItem.list 
    List<Item> returnList = new ArrayList<Item>(); 

    returnList.add(list.get(0); 
    returnList.add(list.get(1); // copy to returnList two Item objects from list (that copied from ListingItem.list) 

    returnList return; 
} 

Другая функция класса Фрагмент использование Fragment.getList() так:

private functionOfFragment() 
{ 
    List<Item> ItemList = getList(); 

    itemList.get(0).ID = 2; 
    itemList.get(1).ID = 2; // changing from 1 to 2 
} 

Однако , значение ListingItem.list.get (0) .ID и Список Item.list.get (0) .ID - также значение . Как это возможно?

obs: ЭТОТ КОД ТОЛЬКО ПРЕДСТАВИТЕЛ, ПРОБЛЕМА НЕ СИНТАКСИСНАЯ ЭРОС!

+0

"каждый присваивает своей переменной ID значение 1". Я не думаю, что у вас действительно есть два объекта в вашем статическом списке. Вы называете «новый» дважды? –

+0

Нужно закрыть parens в 'returnList.add (list.get (0);' –

+0

. Список статических списков из ListItem имеет два объекта Item, но как Fragment может изменить его значение ID, поскольку он получил только копии объектов Item fromListItem.list? –

ответ

2

Параметр, передаваемый по значению в Java, не совпадает с параметром на C++.

В Java:

  • Передача параметров является всегда по значению.
  • Ссылка на объект - это сама переменная, сохраняющая местоположение объекта.
  • Передача справки об объекте передает свое значение.

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

В C++ вы можете сделать это:

#include <iostream> 

class SomeObj { 
public: 
    int num; 
    SomeObj(int n) { 
     num = n; 
    } 
}; 

void reassign(SomeObj* obj) { 
    *obj = *(new SomeObj(5)); 
} 

int main(int argc, char* const argv[]) { 
    SomeObj* obj = new SomeObj(0); 

    reassign(obj); 

    // prints '5' 
    std::cout << obj->num << std::endl; 

    return 0; 
} 

Вы не можете сделать это в Java. Контрольная переменная Java не является указателем на C++, а не ссылкой на C++, а не значением объекта C++.

Вы можете сделать это только:

void reassignLocal(SomeObj* obj) { 
    obj = new SomeObj(5); 
} 

И это:

void mutateElsewhere(SomeObj* obj) { 
    obj->num = 5; 
} 

Так создать новый список, как следующие:

static List<SomeObj> shallowCopy(List<SomeObj> input) { 
    List<SomeObj> output = new ArrayList<SomeObj>(input.size()); 

    for (SomeObj obj : input) 
     output.add(obj); 

    return output; 
} 

только копирует ссылки из одного списка к другому. Это те же объекты. Мутирование output элементов будет мутировать input элементов и наоборот. Чтобы изменить это, вам нужно фактически создать новые объекты.

static List<SomeObj> deepCopy(List<SomeObj> input) { 
    List<SomeObj> output = new ArrayList<SomeObj>(input.size()); 

    for (SomeObj obj : input) 
     output.add(new SomeObj(obj.num)); 

    return output; 
} 
+0

Это очень хорошо ответило. Отлично! Спасибо! –

2

Поскольку переменные относятся к одному и тому же референту. Значение каждой переменной java.lang.Object (например, объектов не примитивов) является ссылочным адресом (например, «запутанным» значением по умолчанию toString()), я надеюсь, что это поможет! Кроме того, это назад returnList return;.

+0

Технически это значение каждого поля переменной или члена в («значение каждого объекта Java» - это объект.) Только ссылки назначаются, передаются и возвращаются. –

+0

@TedHopp Хороший улов! Отредактировано –

+0

В нем должно быть сказано «Значение каждой ссылки на переменные к объекту Java (объект, а не примитив) является адресом объекта. " –

1

Я бы сказал, что в Java мы «передаем ссылки по значению», за исключением примитивов, конечно. В случае примитивов они сами передаются по значению.

+1

Примитивы передаются по значению. – Makoto

+0

Что? Но, если он проходит по значению, как itemList из Fragment.functionOfFragment изменил значение ListItem.list? –

+0

@Neviat В Java переменная объекта всегда является ссылкой. Даже в C++ разность значений/ссылок семантически обманчива, потому что указатели также передаются по значению. Java «всегда проходит по значению», потому что вы не можете выбрать. – Radiodef

3

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

В вашем примере, вы извлекаете Item экземпляры из ArrayList и копии ссылок которые передаются returnList.add. Тем не менее, копии указывают на те же объекты в памяти, что и оригиналы, и все они могут быть «разыменованы» оператором точки.

Это то, что вы делаете, когда говорите itemList.get(1).ID = 2. Поскольку ID является общедоступным, при разыменовании вы получаете доступ к объекту и устанавливаете его значение для чего-то нового.

Таким образом, ссылки на объекты (и примитивы тоже) передаются по значению, но объекты, которые они ссылаются, могут быть изменены в порядке, определяемом API класса. Это не то же самое, что и pass-by-reference, что невозможно в языке, который управляет памятью.

+0

Получил. Спасибо! –

Смежные вопросы