上下文:
- 包数据,公共:
public interface _Data {
public String getData();
}
public class _PackageAPI {
DataHolder holder;
public void createHolder(String data) {
holder = new DataHolder();
holder.setData(data);
}
public void mutateHolder(String data) {
holder.setData(data);
}
public _Data getSnapshot() {
return DataSnapshot.from(holder.getData());
}
public _Data getReader() {
return holder.readOnly();
}
}
- 包数据,包私有:
class DataHolder {
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public _Data readOnly() {
return new _Data() {
@Override
public String getData() {
return DataHolder.this.data;
}
};
}
}
class DataSnapshot {
public static _Data from(String data){
return new _Data() {
@Override
public String getData() {
return data;
}
};
}
}
- 示例客户端用法:
package clientPackage;
import data._Data;
import data._PackageAPI;
public class ExampleRunner {
public static void main(String[] args) {
_PackageAPI handler;
System.out.println("Creating...");
handler = new _PackageAPI();
handler.createHolder("INITIAL DATA");
System.out.println("Done creating...");
_Data initialSnapShot = handler.getSnapshot();
_Data initialReader = handler.getReader();
System.out.println("initialSnapShot holds :" + initialSnapShot.getData() );
System.out.println("initialSnapShot class :" + initialSnapShot.getClass() );
System.out.println("initialReader class :" + initialReader.getClass() );
System.out.println("initialReader holds :" + initialReader.getData() );
System.out.println("Mutating...");
handler.mutateHolder("MUTATED DATA");
_Data subsequentSnapShot = handler.getSnapshot();
_Data subsequentReader = handler.getReader();
System.out.println("Done mutating...");
System.out.println("initialSnapShot holds :" + initialSnapShot.getData() );
System.out.println("initialReader holds :" + initialReader.getData() );
System.out.println("subsequentSnapShot holds :" + subsequentSnapShot.getData() );
System.out.println("subsequentReader holds :" + subsequentReader.getData() );
}
}
- 和控制台输出:
Creating...
Done creating...
initialSnapShot holds :INITIAL DATA
initialSnapShot class :class data.DataSnapshot$1
initialReader class :class data.DataHolder$1
initialReader holds :INITIAL DATA
Mutating...
Done mutating...
initialSnapShot holds :INITIAL DATA
initialReader holds :MUTATED DATA
subsequentSnapShot holds :MUTATED DATA
subsequentReader holds :MUTATED DATA
第一个问题:给定getSnapshot((返回一个_Data(类:DataSnapshot$1(,其方法getData((返回"真实"数据引用,即DataHolder对象的变量数据的内容,这是安全的吗?还是有可能利用对该引用的访问来变异DataHolder?如果是,如何
第一个问题简短:是否有可能仅使用引用来更改引用所引用的内存内容?
(当然,解决方案是克隆被引用的字符串。(
第二个问题:是否存在对DataSnapshot$1(_Data的"不可变"版本(实例进行变异的情况
第三个问题:给定DataHolder$1(_Data的"readOnly"版本(在内部持有对提供它的DataHolder实例的引用,公开这样的DataHolder$1是否安全,或者是否会从DataHolder$1对象中破坏DataHolder实例
编辑:如果有一个,我会放一个paranoïd标签
这是安全的吗?还是有可能利用对该引用的访问对
DataHolder
进行变异?如果是,如何?
由于getData
返回一个不可变的String
,因此调用者不能通过返回的引用更改任何内容。您也不能通过String
访问DataHolder
。为什么String
会知道你的DataHolder
课程?
是否有突变
DataSnapshot$1
的方法?
否,因为它是一个匿名内部类,只有一个返回参数的方法。参数是按值传递的,因此您不必担心调用方在另一端更改其值。它也是一个String
,这意味着调用者也不会改变对象。
您可能会问这个问题,因为您看到initialReader
发生了怎样的变化。好吧,由于DataHolder$1
是可变DataHolder
的内部类,所以即使它没有任何赋值方法,它也不是真正不可变的。
公开这样的
DataHolder$1
是否安全,或者是否会从DataHolder$1
对象中破坏DataHolder
实例?
无法从内部类访问外部类,因此由于DataHolder$1
中没有mutator方法,因此无法从外部对DataHolder
进行突变,只能使用DataHolder$1
。
但是,如果DataHolder
发生变化,这些变化将反映在DataHolder$1
上(如您的示例代码所示(,我认为这违背了不变性的目的。
以下是我在这个场景中如何实现不变性。
我将使DataHolder
实现_Data
。DataHolder
当然能做到,不是吗?毕竟它有一个String getData()
方法!CCD_ 25将具有创建CCD_ 27的副本并返回CCD_ 28的CCD_。事实上,我会将_Data
重命名为ReadOnlyData
。