考虑以下案例。
List<Integer> listOne = new ArrayList<>();
List<Integer> listTwo = new ArrayList<>();
listOne.add(1);I think this happens due to
listOne.add(2);
listOne.add(3);
Collections.reverse(listOne);
listTwo = listOne; //listTwo has same reference
Collections.reverse(listOne);
System.out.println(listOne); //out put [1, 2, 3]
System.out.println(listTwo); // same out put
Java is pass by value, where values (for non primitive types) happen to be references.
我认为这为这种情况提供了java的生存。说实话,java
为什么试图避免pass by reference
并试图与some of other languages
不同?而java仍然受到引用行为的影响?
编辑:另外请一些人解释上面代码中发生的事情
答案 0 :(得分:3)
Java不会受到引用行为的影响,它使它们成为:)
当你写
列表listOne = new ArrayList&lt;&gt;();
您需要考虑三个事项:
1)一个变量,它是一块内存,名为 listOne
2)堆上的一个对象,是一个ArrayList的实例,它是一个更大的内存块,没有名称
3)listOne变量的值,它不是内存块,而是放在变量listOne的内存中的0和1的集合,并且该值也没有名称。
现在,当我们谈论listOne是通过值还是通过引用传递时,我们使用不精确的术语,这会导致误解。 listOne (事物1)根本没有传递,既不是值也不是引用。传递listOne(thing 3)的值,这样就可以访问ArrayList对象(第2项)。因此,如果使用名称“listOne”但是意味着东西3,则通过值传递,如果意味着事情2,则被参照通过。在这两种情况下,名称“listOne”不是东西2或东西3的正确名称,但是因为它简短而方便使用。
答案 1 :(得分:1)
Java是按值传递的。实际参数的副本传递给参数。在原始数据类型的情况下很明显,形式参数的变化没有在实际参数中显示。
static void incre(int a)
{
a++;
}
public static void main (String a[])
{
int c=3;
incre(c);
System.out.println(c); //still prints 3
}
在引用的情况下会发生确切的事情,但是制作引用副本不会创建新对象,它们现在都指向同一个对象。引用所做的更改将反映在此处。
class Demo {
int c =2;
Demo(int c)
{
this.c=c;
}
void incObject (Demo x)
{
(x.c)++;
}
int show()
{
return c;
}
public static void main (String []args)
{
Demo o = new Demo(1);
o.incObject(o);
System.out.print(o.show()); //prints 2
}
}
答案 2 :(得分:0)
Collections.reverse();
修改支持数组。从实施中可以清楚地看出:
public static void reverse(List<?> list) {
int size = list.size();
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
} else {
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for (int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}
现在,listOne
和listTwo
具有相同的引用,指向相同的后备数组。因此,无论哪个句柄(listOne或listTwo)修改后备阵列,另一个将反映相同的更改。在你的情况下:
Collections.reverse(listOne); // backing array has [3,2,1]
listTwo = listOne; //listTwo has same reference
Collections.reverse(listOne); // backing array has [1,2,3]
System.out.println(listOne); //out put [1, 2, 3]
System.out.println(listTwo); // same out put
关于通过value/reference而言。你自己说:
Java是按值传递的,其中值恰好是引用。
为什么java试图避免通过引用传递并尝试与之不同 其他一些语言?
其中一个主要原因是Java(JVM)管理自己的内存。
答案 3 :(得分:-2)
Collections.reverse(listOne);
按值传递对listOne
(对象)的引用,这就是定义“按引用传递”的方式。除了原语之外的所有东西都以这种方式传递:通过引用。它并没有试图避免它,它只是与C ++不同,它不会显式地使用指针。
private static void changelist(List<Integer> list) {
list.add(4);//This modifies the list object
list = new ArrayList<Integer>();//This modifies the local copy of the reference to the list object
list.add(5);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
System.out.println(list);//output is [1,2,3]
//This copies the value of the reference.
//If you modify the object in the underlying
//function, changes will be preserved when you return
//However if you modify what the reference points to,
//the function will only modify the local copy
changelist(list);
System.out.println(list);//output is [1,2,3,4]
}