如何在Java中更改ArrayList元素的值


69

请用下面的代码帮助我,即使更改值也可以获得相同的输出

import java.util.*;

class Test {
    public static void main(String[] args) {
        ArrayList<Integer> a = new ArrayList<Integer>();

       // added 0-9 to ArrayList        
          for(int i=0;i<9;i++)
            a.add(new Integer(i));

        // initialize the Iterator
        Iterator<Integer> i = a.iterator();

        // changed the value of first element in List
        if(i.hasNext()) {
            Integer x = i.next();
            x = Integer.valueOf(9);
        }

        // initialized the iterator again and print all the elements
        i = a.iterator();
        while(i.hasNext())
            System.out.print(i.next());
    }
}    

//Output : 012345678

值9未更新。

Answers:


91

该列表维护着一个对存储在列表中的原始值的对象引用。因此,当您执行此行时:

Integer x = i.next();

x并且该列表被存储到相同的对象的引用。但是,执行时:

x = Integer.valueOf(9);

列表中没有任何变化,但是x现在存储了对另一个对象的引用。列表未更改。您需要使用一些列表操作方法,例如

list.set(index, Integer.valueof(9))

注意:正如其他人所暗示的,这与的不变性无关Integer。这只是基本的Java对象引用行为。


这是一个完整的示例,以帮助解释这一点。请注意,这利用了ListIterator类,该类支持在迭代过程中移除/设置项目:

import java.util.*;

public class ListExample {

  public static void main(String[] args) {

    List<Foo> fooList = new ArrayList<Foo>();
    for (int i = 0; i < 9; i++)
      fooList.add(new Foo(i, i));

    // Standard iterator sufficient for altering elements
    Iterator<Foo> iterator = fooList.iterator();

    if (iterator.hasNext()) {
      Foo foo = iterator.next();
      foo.x = 99;
      foo.y = 42;
    }

    printList(fooList);    

    // List iterator needed for replacing elements
    ListIterator<Foo> listIterator = fooList.listIterator();

    if (listIterator.hasNext()) {
      // Need to call next, before set.
      listIterator.next();
      // Replace item returned from next()
      listIterator.set(new Foo(99,99));
    }

    printList(fooList);
  }

  private static void printList(List<?> list) {
    Iterator<?> iterator = list.iterator();
    while (iterator.hasNext()) {
      System.out.print(iterator.next());
    }
    System.out.println();
  }

  private static class Foo {
    int x;
    int y;

    Foo(int x, int y) {
      this.x = x;
      this.y = y;
    }

    @Override
    public String toString() {
      return String.format("[%d, %d]", x, y);
    }
  }
}

这将打印:

[99, 42][1, 1][2, 2][3, 3][4, 4][5, 5][6, 6][7, 7][8, 8]
[99, 99][1, 1][2, 2][3, 3][4, 4][5, 5][6, 6][7, 7][8, 8]

如果您认为是Integer,则此方法很好,但是如果我使用任何其他对象,该怎么办采取以下情况1)具有两个字段x和y的TempClass 2)在ArraryList a.add(new TempClass)中存储一些对象
prateeksarda 2012年

1
@prateeksarda参见添加到问题的示例。我怀疑您真正想要的是ListIterator课程。我在上面包含了一个示例。
邓肯·琼斯

ListIterator运行正常,但我将其限制为ArrayList集合,如果我使用Set等其他集合,该怎么办
prateeksarda 2012年

注意:正如其他人所暗示的,这与Integer的不变性无关。不是直接的,但是值得一提的是万一x = Integer.valueOf(9)发生了错误的变异尝试x
shmosel

16

使用set方法将旧值替换为新值。

list.set( 2, "New" );

11

您说的是要更改第一个元素的值;

x = Integer.valueOf(9);

您将更x改为指向全新的Integer,但不再使用它。您不会以任何方式更改集合。

由于您正在使用ArrayList,因此,如果要使用允许您更改元素的迭代器,则可以使用ListIterator ,这是需要更改的代码片段。

//初始化Iterator
ListIterator <Integer> i = a。listIterator() ;

//更改了列表中第一个元素的值
if(i.hasNext()){
    i.next();
    i.set(Integer.valueOf(9));     //更改迭代器当前所在的元素
}

//新的迭代器,并打印所有元素
Iterator iter = a.iterator();
while(iter.hasNext())
    System.out.print(iter.next());

>> 912345678

可悲的是,它不能扩展到其他集合,例如Set <T>。实现细节(例如,将HashSet实现为哈希表并更改对象可能会更改哈希值,因此会改变迭代顺序)使Set <T>成为“仅添加/删除”数据结构类型,并更改内容根本无法迭代。


所以该怎么办...我该如何更改收藏夹?
prateeksarda

@prateeksarda添加了使用ListIterator的示例。
约阿希姆·伊萨克森

@prateeksarda添加了有关迭代的信息Set<T>
约阿希姆·伊萨克森

Iterator似乎没有set()方法,因为错误:正在返回“对于Iterator <Float>类型,未定义方法set(Float)”。
艾迪·库玛

1

您正在尝试更改列表中的值,但是您所做的只是更改x的引用。进行以下操作仅更改x,而不更改集合中的任何内容:

x = Integer.valueOf(9);

此外,它Integer是不可变的,这意味着您无法更改Integer对象内的值(无论如何,这都需要使用其他方法来完成)。这意味着您需要替换整个对象。没有办法Iterator(不添加自己的拳击层)来执行此操作。而是执行以下操作:

a.set(0, 9);

1
的不变性Integer无关紧要。
邓肯·琼斯

@DuncanJones不,实际上不是。如果Integer是可变的,可能会存在诸如say这样的方法changeValue(int)。但是,由于它是不可变的,因此我们知道这种方法不存在。
CrazyCasta

很好,但是我担心这不会影响为什么该代码示例不起作用。即使使用可变的类,该代码也无法达到OP的期望-尝试一下。
邓肯·琼斯

正如我在回答的第一句话中所解释的:“您正在尝试更改列表中的值,但您所做的就是更改x的引用。”
CrazyCasta 2012年

我明白那个。我并不是说答案不正确(因此没有否决权)。我只是建议您在提及与问题无关的不可变性时可能会引起混淆。
邓肯·琼斯

1

我同意Duncan ...我已经尝试了可变对象,但仍然遇到相同的问题...我得到了一个简单的解决方案...使用ListIterator代替Iterator并使用ListIterator的set方法

ListIterator<Integer> i = a.listIterator();
//changed the value of first element in List
Integer x =null;
        if(i.hasNext()) {
            x = i.next();
            x = Integer.valueOf(9);
        }
    //set method sets the recent iterated element in ArrayList
    i.set(x);
        //initialized the iterator again and print all the elements
        i = a.listIterator();
        while(i.hasNext())
        System.out.print(i.next());

但这限制了我只能将其用于可以使用ListIterator的ArrayList ...其他任何Collection都会遇到相同的问题


1

我认为问题在于您认为该声明...

x = Integer.valueOf(9);

...导致'9'的值被“存储”到(!)x所引用的对象中。

但这是错误的。

相反,该语句会导致类似的结果,就像您将调用

x = new Integer(9); 

如果看一下Java源代码,您将看到Detail中发生的事情。

这是“ Integer”类中“ valueOf(int i)”方法的代码:

public static Integer valueOf(int i) {
    assert IntegerCache.high >= 127;
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

此外,每当首次使用IntegerCache类时,都会调用以下脚本:

static {
        // high value may be configured by property
        int h = 127;
        String integerCacheHighPropValue =
            sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
        if (integerCacheHighPropValue != null) {
            int i = parseInt(integerCacheHighPropValue);
            i = Math.max(i, 127);
            // Maximum array size is Integer.MAX_VALUE
            h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
        }
        high = h;

        cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
    }

您会看到,或者在valueOf方法中使用“ new Integer(i)”创建了一个新的Integer对象,或者返回了对存储在IntegerCache中的Integer对象的引用。

在两种情况下,x都将引用一个新对象。

这就是为什么在调用...时丢失对列表中Object的引用的原因。

x = Integer.valueOf(9);

而不是这样做,与ListIterator结合使用...

i.set(Integer.valueOf(9));

...获得元素后,您想要...

i.next();

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.