【问题标题】:How to change value of ArrayList element in java如何在java中更改ArrayList元素的值
【发布时间】:2012-09-28 03:44:27
【问题描述】:

请帮助我使用下面的代码,即使更改值后我也会得到相同的输出

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 未更新。

【问题讨论】:

    标签: java arraylist


    【解决方案1】:

    列表正在维护对存储在列表中的原始值的对象引用。所以当你执行这一行时:

    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) TempClass 有两个字段 x 和 y 2) 在 ArraryList a.add(new TempClass )
    • @prateeksarda 查看添加到问题的示例。我怀疑你真正想要的是ListIterator 类。我已经在上面包含了一个例子。
    • ListIterator 工作正常,但它限制了我使用 ArrayList 集合,如果我使用任何其他集合,如 Set
    • 注意:这与 Integer 的不变性无关,正如其他人所暗示的那样。 不是直接的,但如果 x = Integer.valueOf(9) 是变异x的错误尝试。
    【解决方案2】:

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

    list.set( 2, "New" );
    

    【讨论】:

      【解决方案3】:

      你说你要改变第一个元素的值;

      x = Integer.valueOf(9);
      

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

      由于您使用的是 ArrayList,如果您想要一个允许您更改元素的迭代器,您可以使用 ListIterator,这是需要更改的代码的 sn-p ;

      //初始化迭代器
      ListIterator i = a.listIterator();

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

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

      >> 912345678

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

      【讨论】:

      • 那么该怎么做...我怎样才能更改收藏?
      • @prateeksarda 添加了您的示例使用 ListIterator 的样子。
      • @prateeksarda 添加了一些关于迭代 Set&lt;T&gt; 的信息。
      • Iterator 似乎没有 set() 方法,因为错误:“方法 set(Float) is undefined for the type Iterator”正在返回。
      【解决方案4】:

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

      x = Integer.valueOf(9);
      

      此外,Integer 是不可变的,这意味着您无法更改 Integer 对象内的值(无论如何这都需要不同的方法)。这意味着您需要替换整个对象。没有办法用Iterator 做到这一点(不添加你自己的拳击层)。请改为执行以下操作:

      a.set(0, 9);
      

      【讨论】:

      • Integer 的不变性无关紧要。
      • @DuncanJones 不,实际上不是。如果Integer 是可变的,则可能存在像changeValue(int) 这样的方法。但是,由于它是不可变的,我们知道这样的方法是不存在的。
      • 很好,但恐怕这不会影响代码示例为什么不起作用。即使使用可变类,代码也不会像 OP 期望的那样执行 - 试试吧。
      • 正如我在回答的第一句话中已经解释的那样“您正在尝试更改列表中的值,但您所做的只是更改 x 的引用。”
      • 我明白这一点。我并不是说答案不正确(因此没有反对票)。我只是建议您在与问题无关时提及不变性可能会造成混淆。
      【解决方案5】:

      我同意 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 相同的问题

      【讨论】:

        【解决方案6】:

        我认为问题在于你认为语句...

        x = Integer.valueOf(9);
        

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

        但那是错误的。

        相反,该语句会导致类似的事情,就好像你会调用

        x = new Integer(9); 
        

        如果您查看 java 源代码,您会看到详细的内容。

        下面是“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)”创建了一个新的整数对象... ... 或返回对存储在 IntegerCache 中的 Integer 对象的引用。

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

        这就是为什么当您调用时对列表中对象的引用会丢失...

        x = Integer.valueOf(9);
        

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

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

        ...在您获得要更改的元素后...

        i.next();
        

        【讨论】:

          【解决方案7】:

          改成for(int i=0;i&lt;=9;i++)

          【讨论】:

            猜你喜欢
            • 2015-05-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-03-30
            相关资源
            最近更新 更多