【问题标题】:Iterations over a private list questions对私人列表问题的迭代
【发布时间】:2013-06-25 09:46:30
【问题描述】:

我有一个课程 SomeClass,里面有一个 List<String> someList。我需要让其他类遍历列表元素,但不让它们更改列表或列表元素。测试以下代码:

public class SomeClass {
    static private List<String> someList;

    public static List<String> getSomeList() {
        return someList;
    }
    SomeClass(Array<String> someArray){
        someList=Collections.unmodifiableList(Arrays.asList(someArray));
    }

}
public class DoSomething {
    for (String s : SomeClass.getSomeList()){
    s+="Gotcha";
    }
}

将显示 s 只会在该 for 循环内更改 - 一旦完成 getSomeList() 将返回良好的旧列表,因此不会保存任何更改。尝试调用 getSomeList().add("someString") 也会导致异常:UnsupportedOperationException。 请(向资深 C 编码人员)解释这种行为背后的逻辑以及如何捕获该异常?

【问题讨论】:

  • 您没有显示足够的SomeClass。在尝试调用 add() 时,我看不到 UnsupportedOperationException 的原因。
  • @jlordo:我已经添加了缺少的代码行(我认为)
  • 这甚至不会编译...

标签: java list exception-handling iteration private


【解决方案1】:

String 的+= 操作符实际上创建了一个新的String 实例,而不是修改您的原始字符串对象。也就是说,下面两行代码是等价的:

s += "Gotcha"
s = new String(s + "Gotcha");

示例

下面是一个与你的doSomeThing类似的例子

public class st {
  public static void main(String[] args) {
    String hello = "hello";
    String helloReference = hello; // making helloReference and hello refer to same object.
    helloReference += " world"; // perform +=
    System.out.format("`hello` = %s, `helloReference` = %s\n",
        hello, helloReference);
  }
}

其输出如下,说明hello引用的对象不受helloReference执行的+=操作符的影响:

hello = `hello`, helloReference = `hello world`

在其他世界中,在 += 运算符之前:

    hello            helloReference
      |                     |
   -------------------------------
   |        "hello"              |
   -------------------------------

在 += 运算符之后,它会创建一个新实例并修改helloReference 引用的对象:

    hello            helloReference
      |                     |             --------------------
      |                     --------------|   "hello world"  |
   -------------------------------        --------------------
   |        "hello"              |
   -------------------------------

所以你的代码是安全的,在你 doSomeThing 中执行的操作会影响你的 SomeClass 引用的对象:

public class DoSomething {
  for (String s : SomeClass.getSomeList()){
    // this create an new string instance to s
    s+="Gotcha"; 
  }
}

【讨论】:

  • 你的意思是java传递引用而不是指针。有没有办法在 Java 中传递指针(这就是我所说的 C 程序员......)。并为文本图形 +1。
  • 只是=在Java中可以传递引用,不同的是String的不变性,需要时会创建一个新的实例。
  • 对于那些被设计为不可变的类,创建后你无法更改它。
【解决方案2】:

对于列表,使用Collections.unmodifiableList() 返回一个外部不可修改的列表(即,您仍然可以在SomeClass 内修改列表)。

public List<String> getInternalList() {
  return Collections.unmodifiableList(someList);
}

对于 String,返回是安全的,因为 String 是 immutable class

【讨论】:

    【解决方案3】:

    一旦完成 getSomeList() 将返回良好的旧列表,所以没有 更改已保存。

    因为Stringimmutable,所以更改不会反映在最终列表中。使用StringBuilderStringBuffer 而不是String 作为列表的元素。

    同时尝试调用 getSomeList().add("someString") 将导致 异常:UnsupportedOperationException。

    因为,Arrays.asList(someArray) 正在返回 Arrays.ArrayList,它是在 Arrays 类中定义的嵌套类,如下所示:

    private static class ArrayList<E> extends AbstractList<E>
             implements RandomAccess, java.io.Serializable
    

    而且这个类正在扩展AbstractList,而后者又扩展了AbstractCollection。嵌套类ArrayList 没有覆盖AbstractListadd(E e) 方法。因此,当您在此 List 上调用 add() 时,它会调用 AbstractCollectionadd(E e) 方法,该方法在其中定义如下:

    public boolean add(E e) {
                 throw new UnsupportedOperationException();
            }
    

    这就是为什么您在调用add("something") 时收到UnsupportedOperationException

    【讨论】:

      【解决方案4】:

      字符串是不可变的对象,所以你不能那样改变它们。

      其次,你不能在类体中执行代码。 DoSomething 类应该有这样的方法:

      public class DoSomething {
      
          public static void doSomething() {
               //code            
          }
      }
      

      【讨论】:

        【解决方案5】:

        来自 javadoc , List stooges = Arrays.asList("Larry", "Moe", "Curly") ,它会给你一个返回一个由指定数组支持的固定大小的列表。 所以对这个列表的任何修改都会导致 java.lang.UnsupportedOperationException,即使代码中没有以下内容 Collections.unmodifiableList(Arrays.asList(someArray));

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-04-01
          • 1970-01-01
          • 2012-12-14
          • 2015-10-11
          • 1970-01-01
          • 1970-01-01
          • 2020-06-22
          • 2015-12-26
          相关资源
          最近更新 更多