这与此问题相反:为什么字符串在Java和.NET中不可变?
这种选择是否仅仅因为操作(追加等)在可变字符串上有效,或者是否有其他原因而在Ruby中进行?
(如果它只是效率,那似乎很奇怪,因为Ruby的设计似乎不会高度重视促进有效的实施.)
假设我将银行账户信息存储在一个不可变的Map:
val m = Map("Mark" -> 100, "Jonathan" -> 350, "Bob" -> 65)
Run Code Online (Sandbox Code Playgroud)
我想从马克的帐户中提取50美元.我可以这样做:
val m2 = m + ("Mark" -> (m("Mark") - 50))
Run Code Online (Sandbox Code Playgroud)
但这段代码对我来说似乎很难看.有没有更好的方法来写这个?
关于id类型对象的某些东西str(在python 2.7中)让我很困惑.该str类型是不变的,所以我希望,一旦它被创建,它将始终具有相同的id.我相信我不会这么说自己,所以我会发布一个输入和输出序列的例子.
>>> id('so')
140614155123888
>>> id('so')
140614155123848
>>> id('so')
140614155123808
Run Code Online (Sandbox Code Playgroud)
所以同时,它一直在变化.但是,在指向该字符串的变量之后,事情会发生变化:
>>> so = 'so'
>>> id('so')
140614155123728
>>> so = 'so'
>>> id(so)
140614155123728
>>> not_so = 'so'
>>> id(not_so)
140614155123728
Run Code Online (Sandbox Code Playgroud)
因此,一旦变量保存该值,它就会冻结id.的确,在del so和之后del not_so,id('so')开始的输出再次改变.
这是不相同的行为与(小)整数.
我知道不变性和拥有相同之间没有真正的联系id; 仍然,我试图弄清楚这种行为的来源.我相信那些熟悉python内部的人会比我更少惊讶,所以我试图达到同样的目的......
尝试使用不同的字符串会产生不同的结果......
>>> id('hello')
139978087896384
>>> id('hello')
139978087896384
>>> id('hello')
139978087896384
Run Code Online (Sandbox Code Playgroud)
现在它是平等的......
JavaDoc ImmutableSet说:
与
Collections.unmodifiableSet可以更改的单独集合的视图不同,此类的实例包含其自己的私有数据,并且永远不会更改.这个类对于公共静态最终集("常量集")很方便,也可以让你轻松地为调用者提供给你的类的集合制作一个"防御性副本".
但ImmutableSet仍然存储元素的参考,我无法弄清楚差异Collections.unmodifiableSet().样品:
StringBuffer s=new StringBuffer("a");
ImmutableSet<StringBuffer> set= ImmutableSet.of(s);
s.append("b");//s is "ab", s is still changed here!
Run Code Online (Sandbox Code Playgroud)
谁能解释一下呢?
在我的代码中,我正在创建一个对象集合,这些对象将以各种线程的方式访问,只有在对象是不可变的情况下才是安全的.当尝试将新对象插入到我的集合中时,我想测试它是否是不可变的(如果没有,我会抛出异常).
我能做的一件事就是检查一些众所周知的不可变类型:
private static final Set<Class> knownImmutables = new HashSet<Class>(Arrays.asList(
String.class, Byte.class, Short.class, Integer.class, Long.class,
Float.class, Double.class, Boolean.class, BigInteger.class, BigDecimal.class
));
...
public static boolean isImmutable(Object o) {
return knownImmutables.contains(o.getClass());
}
Run Code Online (Sandbox Code Playgroud)
这实际上让我90%的方式,但有时我的用户会想要创建自己的简单不可变类型:
public class ImmutableRectangle {
private final int width;
private final int height;
public ImmutableRectangle(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() { return width; }
public int getHeight() { return height; }
}
Run Code Online (Sandbox Code Playgroud)
是否有某种方式(可能使用反射)我可以可靠地检测一个类是否是不可变的?假阳性(认为它不是不可变的)是不可接受的,但是假阴性(认为它是可变的,当它不是)时.
编辑补充:感谢有见地和有帮助的答案.正如一些答案所指出的那样,我忽略了我的安全目标.这里的威胁是无能为力的开发人员 - 这是一个框架代码,将被大量知道线程无关的人使用,不会阅读文档.我不需要为恶意开发者辩护 - 任何聪明到足以变异字符串 …
为了减少可变性,我们应该使用
public void setValues(String[] newVals) {
this.vals = ( newVals == null ? null : newVals.clone() );
}
Run Code Online (Sandbox Code Playgroud)
要么
public void setValues(String[] newVals) {
this.vals = ( newVals == null ? null : Arrays.copyOf(newVals, newVals.length) );
}
Run Code Online (Sandbox Code Playgroud) 我想写这样的东西:
var d = new ImmutableDictionary<string, int> { { "a", 1 }, { "b", 2 } };
Run Code Online (Sandbox Code Playgroud)
(使用ImmutableDictionary来自System.Collections.Immutable).这似乎是一个简单的用法,因为我预先声明了所有的价值 - 那里没有变异.但这给了我错误:
类型'
System.Collections.Immutable.ImmutableDictionary<TKey,TValue>'没有定义构造函数
我应该如何用静态内容创建一个新的不可变字典?
public class Test {
private final String url;
public Test(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
}
Run Code Online (Sandbox Code Playgroud)
Test类有:
但是我正在阅读的一本书说上面的Test类是可变的,因为:
这两个类都不是最终的,因此它可以扩展,并且子类可以覆盖实例方法.但Test类实际上没有构造函数以外的任何实例方法.
构造函数也不是私有的.
你能帮我理解为什么Test类是可变的吗?
我经常读到structs应该是不可变的 - 根据定义它们不是吗?
你认为int是不可改变的吗?
int i = 0;
i = i + 123;
Run Code Online (Sandbox Code Playgroud)
似乎没关系 - 我们得到一个新的int并将其分配给i.那这个呢?
i++;
Run Code Online (Sandbox Code Playgroud)
好的,我们可以把它想象成一条捷径.
i = i + 1;
Run Code Online (Sandbox Code Playgroud)
怎么样struct Point?
Point p = new Point(1, 2);
p.Offset(3, 4);
Run Code Online (Sandbox Code Playgroud)
这真的改变了这一点(1, 2)吗?我们难道不应该将它视为Point.Offset()返回新点的下列捷径吗?
p = p.Offset(3, 4);
Run Code Online (Sandbox Code Playgroud)
这种想法的背景是这样的 - 没有身份的价值类型怎么可能是可变的?您必须至少查看两次以确定它是否发生了变化.但是如果没有身份,你怎么能这样做呢?
我不想通过考虑ref参数和拳击来使这个推理复杂化.我也知道,p = p.Offset(3, 4);表达不变性比做得好p.Offset(3, 4);.但问题仍然存在 - 根据定义,值不是不可变的值吗?
UPDATE
我认为至少涉及两个概念 - 变量或字段的可变性以及变量值的可变性.
public class Foo
{
private Point point; …Run Code Online (Sandbox Code Playgroud) 例如,我从文本文件中提取文本字符串,我需要这些字来形成一个数组.但是,当我做所有这些时,一些单词以逗号(,)或句号(.)结尾,或者甚至附加括号(这都是完全正常的).
我想要做的就是摆脱那些角色.我一直试图在Java中使用那些预定义的String方法来做到这一点,但我无法解决它.