class Some{
private int id;
private String name;
//getters and setters
}
class Check{
private Some[] someVals;
//getters and setters
}
假设我已将值填充到Check类
中的someVals中void newMethod(){
Check checkPrev = getCheckPopulated();
Some[] someFirst = checkPrev.getSomeVals();
modifySome(someFirst);
Some[] some = ? // at this point need the values of someFirst
}
我的问题是即使在修改之后(我指定的地方)也得到Some []数组的值,即分配时首先出现的值。
很好,我会清楚地提出问题。 final Some [] someFirst = checkPrev.getSomeVals();不工作 通过保留数组值而不必将所有值重新分配给另一个数组,是否有类似于final的小提示?
答案 0 :(得分:3)
你也不能吃蛋糕。您必须制作该对象的深层副本,然后修改原始副本。然后,深层副本将包含原始值。
答案 1 :(得分:1)
在modifySome方法中,返回一个新的Some []数组。
Some[] modifySome(Some[] passedArray){
Some[] result = new Some[passedArray.length];
System.arraycopy( passedArray, 0, result , 0, a.length );
//Modify result as needed
return result
}
如果你可以修改一些返回一个数组,你的代码可以改为:
Some[] some = modifySome(someFirst);
在该行之后,someFirst
仍将与之前相同,some
将是修改后的值。
答案 2 :(得分:0)
一种选择是使用CopyOnWriteArrayList。
CopyOnWriteArrayList<Some> someFirst = checkPrev.getSomeVals();
Iterator iterator = someFirst.iterator();
modifySome(some);
迭代器仍将引用原始列表,而不是修改后的列表。
另一种选择是制作原始数组的副本。
Some[] someFirst = checkPrev.getSomeVals();
Some[] someCopy = new Some[someFirst.length];
System.arrayCopy(someFirst, 0, someCopy, 0, someFirst.length);
modifySome(some);
someCopy
仍将保留原始数组的副本。
答案 3 :(得分:0)
欢迎来到可变的Java bean世界。
你无法做你想做的事......但这是一个使用我写的几个接口的解决方案:
// Both classes in the same package
@Immutable // by contract
class Some implements Frozen<SomeBuilder>
{
// All fields are final, package local
final String name;
// getters only -- NO setters
public Some(final SomeBuilder builder)
{
name = builder.name;
// other
}
// Return a thawed version
@Override
public SomeBuilder thaw()
{
return new SomeBuilder(this);
}
}
@NotThreadSafe // by contract
class SomeBuilder implements Thawed<Some>
{
// Mutable fields here, package local
String name;
// other
// To create a new builder
public SomeBuilder()
{
}
// Package local constructor
SomeBuilder(final Some some)
{
name = some.name;
// etc
}
// Mutations
public SomeBuilder setName(final String name)
{
this.name = name;
return this;
}
// Return a frozen version
@Override
public Some freeze()
{
return new Some(this);
}
}
现在,关于修改功能,让它返回一个新数组。并使用.freeze()
/ .thaw()
从现有实例创建Some
的新实例。
答案 4 :(得分:0)
Java的一个缺点是基本上只有一种非原始类型:混杂的堆对象引用。类George
的实例在其包之外保存对类Foo
的对象Bar
的引用无法与外部代码共享该引用,而不会将该外部代码赋予永久性能够对Foo
George
可以做的任何事情做任何事情。 Java的部分设计目标即使在简单的硬件系统上也易于实现,并且具有单个非基本类型有助于实现该目标。另一方面,它还意味着程序员需要跟踪哪些对象引用用于封装:
除了身份之外的对象状态的不可变方面,即使持有引用的代码也无法更改。
对象标识(以及可能是其他状态的不可变方面)
对象状态的方面是可变的,除了预期它们永远不会被赋予实际改变它们的代码,而不是身份。
对象状态的可变方面,这些方面由拥有引用但不具有标识的代码“拥有”。
对象状态的可变方面,以及身份。
在你的代码中,因为数组是可变的,你的数组类型字段不能具有第一个含义,但它可以保存其他四个中的任何一个。此外,数组的元素可以包含任何上述类型的东西。如果您认为对象的状态是其数组中保存的id
和name
对的组合,那么id
和/或name
的{{1} Some
持有引用的对象可以更改,如果这样的更改将被视为Check
状态的更改,则制作副本Check
的状态需要创建一个新数组,并用新的Check
实例填充它,其数据是从原始数组中的相应实例复制的。
如果数组中的Some
个对象都不会暴露给可能会改变它们的代码,那么就没有必要构造单个Check
个对象的新实例;创建一个新数组并使用对原始数组中对象的引用来填充它就足够了。同样,如果数组的目的是封装在其他位置定义的Check
个对象的标识,那么对这些对象的更改将不会被视为对Check
的更改州。请注意,在前一种情况下(对象永远不会更改),用保存相同数据的新实例替换Check
对象将效率低下但不会破坏任何内容。在后一种情况下(数组封装了对象的标识,而不是它们的状态),用新实例的引用替换引用会破坏代码。
虽然许多人谈论“深度克隆”或“浅层克隆”,但这种术语主要源于对各种对象引用应该封装的内容缺乏明确性。如果对象Some
具有类型类型字段,该字段封装Fred
拥有的可变状态(但不包含身份),则Fred
的副本应该包含对该副本的引用宾语。如果字段封装了不可变状态,则Fred
的副本可以保存对原始对象或其任何不可变副本的引用。如果它封装了身份,则Fred
的副本必须保存对原始对象的引用 - 而不是副本。如果它封装了身份和可变状态,则无法复制Fred
而不复制它所属的相互连接对象的整个林。