我有一个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编码员)这种行为背后的逻辑以及如何捕获该异常?
答案 0 :(得分:2)
对于列表,使用Collections.unmodifiableList()返回外部无法修改的列表(即,您仍然可以修改SomeClass
中的列表。)
public List<String> getInternalList() {
return Collections.unmodifiableList(someList);
}
对于String,返回是安全的,因为String是immutable class。
答案 1 :(得分:2)
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";
}
}
答案 2 :(得分:2)
一旦完成,getSomeList()将返回好的旧列表,所以没有 保存更改。
因为,String
为immutable所以更改未反映在最终列表中。使用StringBuilder
或StringBuffer
代替String
作为元素列表。
同时尝试调用getSomeList()。add(“someString”)将导致 exception:UnsupportedOperationException。
因为,Arrays.asList(someArray)
返回Arrays.ArrayList
,这是Arrays
类中定义的嵌套类,如下所示:
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
此课程正在扩展AbstractList
,而AbstractCollection
则会延伸add(E e)
。嵌套类ArrayList
未覆盖AbstractList
的{{3}}方法。因此,当您在此add()
上致电List
时,它会调用AbstractCollection
public boolean add(E e) {
throw new UnsupportedOperationException();
}
方法,该方法在其中定义如下:
add("something")
这就是您在致电{{1}}时获得add(E e)
的原因。
答案 3 :(得分:1)
字符串是不可变的对象,因此您无法像这样更改它们。
其次,您无法在类体中执行代码。 DoSomething
类应该有一个方法来执行该操作:
public class DoSomething {
public static void doSomething() {
//code
}
}
答案 4 :(得分:0)
来自javadoc, List stooges = Arrays.asList(“Larry”,“Moe”,“Curly”),它将为您提供返回由指定数组支持的固定大小列表。 因此,即使代码中没有以下内容,对此列表的任何修改都将导致java.lang.UnsupportedOperationException Collections.unmodifiableList(Arrays.asList(的someArray));