为什么Wrapper类(如Integer,Double等)没有内部原始值的setter,这是什么原因?
我问这个是因为这种功能会简化微积分,并使Java语言更灵活一些。
让我举几个例子。
1)我们采取以下示例:
Integer x = new Integer(5);
x++;
幕后的前一个代码是执行自动装箱。类似的东西:
int x_tmp = x.intValue();
x_tmp++;
x = new Integer(x_tmp); // Yes that's a new memory allocation
由于这个问题,在Wrapper上执行微积分比在普通原始类型上执行要慢。使用setter,可以更容易地增加内部值,而无需在堆上分配另一个对象。
2)另一个困扰我的问题是,在Java中编写交换函数是不可能的,就像我可以在C(使用指针)或C ++(指针或引用)中那样。
如果我写void swap(Integer x, Integer y)
我无法访问内部值,因为我将无法交换这些值。
PS: 我的一个朋友建议我应该考虑更大的图景,并考虑并发性和类型不变性。
那你有解释吗? 谢谢!
答案 0 :(得分:6)
通常不使用包装类,除非您需要将它们放入集合中。如果它们是可变的,那么如果在集合内部使用并且作为哈希表的键,则会产生问题。
集合和哈希表需要哈希值始终相同。
答案 1 :(得分:4)
1)使用setter,包装器类型是可变的。不变性在很多方面都是一件好事......线程,代码的一般可理解性等。我个人认为,例如Calendar
和Date
是可变的,这是一种耻辱。
事实上,您对x++;
的扩展并不十分正确 - 它使用Integer.valueOf
不始终创建新值。例如:
Integer x = 5;
x++;
Integer y = 5;
y++;
// This prints true
System.out.println(x == y); // Compare references
只有有限范围的Integer
值被缓存(规范定义了必须的行为方式,但如果JRE希望这样做,则允许更宽的范围) ...但它确实意味着它不会总是创建一个新对象。
2)是的,Java没有通过引用传递。坦率地说,我很少发现这是一个问题。您经常需要交换变量值吗?
答案 2 :(得分:4)
缓存在-128到127范围内的整数需要不可变的整数。考虑以下代码:
Integer id = Integer.valueOf(1); // a new Integer, cached in Integer class
// and somewhere else
Integer key = Integer.valueOf(1); // returns the cached value
现在如果整数是可变的并且有一个setter而且有人做了
key.setValue(2); // not legal Java code, just for demonstration
这也会改变id
的价值,让很多人感到惊讶:
Integer one = Integer.valueOf(1);
if (one != 1)
System.out.println("Surprise! I know, you expected `1`, but ...");
答案 3 :(得分:1)
在Java中,字符串和包装类被设计为不可变的,以避免意外更改数据。您可以查看以下文章以获取更多信息。