Java是否对Integer,Float,Double,Long具有可变类型?


81

我处于一种想要使用可变版本(例如Integer)的情况。我必须使用这些类(下面)还是Java内置一些东西?

http://www.java2s.com/Code/Java/Data-Type/Amutableintwrapper.htm


8
问题是您为什么要这样做?
helpermethod 2010年

2
在某些情况下(例如,游戏中,存储着一块n可以消耗/添加热量的食物),最好使用使用后命名的类(例如class FoodItem { int calories; },因为这样更清晰,方法可以
GKFX

7
Java 8 lambda仅与有效的最终变量一起使用。要解决此限制,需要一个可变的int。
Alex

您可能想要一个需要在方法之间传递的计数器。传递anint无效,就好像它在一种方法中递增一样,那么该值将不会在另一种方法中反映出来。
亚当·伯利

Answers:


51

不,Java没有内置这些​​功能。这是有原因的。使用可变类型很危险,因为它们很容易被滥用。另外,实现它真的很容易。例如,commons-lang有一个MutableInt


5
我的猜测是Java开发人员希望Integer像int一样“表现”,即..一旦您引用了它,它就永远不会改变(避免混淆)。但是..对于我来说,没有可变的选择似乎仍然很奇怪……
rogerdpack

35
“使用可变类型是危险的,因为它们很容易被滥用。” 大多数事情都可能被滥用。对于安全性很重要的情况,存在不可变类型,尽管可以通过反射来更改它们。有了这些案例,没有理由阻止人们在需要时使用可变类型。
GKFX

2
更好的表达方式是,不可变类型在地图和集合中减少混乱。如果您有一个可变的Integer并在用作键的位置更改了它的值,那么它将弄乱集合。但是,如果您需要某种可变的Integer实现,则没有比在内部创建一个带有int值的类更容易的了。您可以在这里发挥创造力-使其成为一个计数器或倒数计时,而不仅仅是一个可以实现任何功能的简单整数。给它一些逻辑(除非您使用自底向上的Java EE开发)。
Vlasec 2014年

当然是一个老问题,但是希望有人能够回答他们如何被滥用。使用它们有什么危险?
蓬松的机器人

@ user1175807正如Vlasec所评论的那样,如果您不小心修改了在其他地方使用的变量,则将导致奇怪的错误。更糟糕的是,假设您正在编写与客户代码一起使用的程序。您需要实现一个具有可变Integer类型参数的方法。现在,如果出于任何原因修改了可变Integer,那么它也将在客户端程序中更改,这完全是意外的,并且会导致难以发现的错误。
GregT

90

您总是可以将值包装在数组中,就像int[] mutable = {1};包含可变包装类的代码太麻烦一样。


30
聪明,臭虫像罪恶。
gvlasov

2
这是超级聪明,几乎不占用空间。此外,还避免了使用AtomicInt进行的加密。
CompEng88 '18年

52

从JDK 1.5开始,java现在有了 java.util.concurrent.atomic.AtomicInteger

这是线程安全的可变整数,使用示例:

final AtomicInteger value = new AtomicInteger(0);

然后再:

value.incrementAndGet();

12
这种安全性是以性能为代价的,在许多情况下是不需要的。例如,对我来说,一个常见的用例是增加由lambda捕获的计数器。使用原子是多余的。
米纳斯米纳

12

这是我为可变整数创建的一个小类:

public class MutableInteger {
    private int value;
    public MutableInteger(int value) {
        this.value = value;
    }
    public void set(int value) {
        this.value = value;
    }
    public int intValue() {
        return value;
    }
}

您可以轻松地将此扩展到其他任何原语。当然,就像其他人说的那样,您应该谨慎使用它。


1
恕我直言,最好的选择是它不会像使用原子整数那样提供关于并发的错误线索。还有一个数组,真的我永远不会在我的代码中做这样的坏事。;)
Snicolas

可能是一个好主意,提供一个通用的包装类,而不是让你不带结束了MutableIntegerMutableDoubleMutableString等而是有Mutable<Integer>Mutable<Double>,...(使用的内存开销Integer超过int通常不会落入帐户,但
–Qw3ry

扩展Number可能是一个好主意。
Stijn de Witt

7

您可以使用nnnn []作为任何原始类型的可变对象,如@Alexandre所建议的那样,java还具有AtomicInteger和AtomicLong。

IMHO int通常是比Integer更好的选择,并且是可变的。

您能否详细说明为什么需要一个多重对象,也许还有另一种方法可以实现相同的目的。


8
int不可变。
mjaggard 2012年

7
int除非它也总是可变的final
彼得·劳瑞

18
说基本类型是可变的并不能真正有效。可以更改它,但是如果您只是指向一个新对象,那么每个非最终对象也可以更改。例如,Integer a = 4;然后a = 5;是有效代码,但Integer不是可变的。
mjaggard '02

我同意Integer即使引用是实例也不可变,但这是另一种类型。
彼得·劳瑞

1
int是不可变的,因为如果将其传递给方法,则该方法无法更改其值并使新值反映在调用方法中
Adam Burley

5

AtomicInteger已经提到过。可变Double可以使用来模拟AtomicReference<Double>。前面已经提到过警告,但它的样式不好,但有时您会遇到类似这样的代码

double sum=0
for (Data data:someListGenerator())
  sum+=data.getValue()

并希望以实用的Java 8样式对其进行重构。如果代码遵循此模式,但给它增加了相当大的复杂性,则最明智的转换可能

AtomicReference<Double> sumref=new AtomicReference<>(0d);
someStreamGenerator().forEach(data->
  sumref.set(sumref.get().doubleValue()+data.getValue()));
double sum=sumref.get().doubleValue();

当然,这至少是可疑的风格。但是我不止一次地发现自己处于一种扭曲的ResultSet计算循环中,并且部分地累积了三个不同的信息。这使得将代码转换为适当的功能样式真的很困难。在我看来,按照上述模式转换累计部分似乎是在干净代码和简化过的重构之间进行合理的权衡。


您应该真正考虑一下您的措辞:即使您使用lambda,您的示例也不起作用,因为它禁止了副作用。如果您确实将其编写为实用程序,则不需要可变项:someStreamGenerator().mapToDouble(Data::getValue).sum()。即使累积三个不同的信息,也可以使用或来实现功能。我认为没有理由将每个循环重构为一个功能代码片段,但是如果您要那样做,则应将其循环到最后。Stream.reduceStream.collect
Tobias Liefke '18

正如我说:这是正确的风格,为每本应任何新代码被使用。但是重构400.000+线中的哪内15年发展的代码时,你会发现这里构造适当改写成真正的功能构建物可以是极其困难的。然后,重写这种混合样式可能是明智的权衡,因为您至少要使基本结构保持一致。for并且foreach可以是功能上经过重写的复杂框架的一部分,因此您必须以某种方式将其余代码对齐。
德克·希尔布雷希特

您会混淆lambda和函数式编程。在您的示例中,您没有将其重写为“功能性”。当您失去可读性但又没有获得函数编程的优势时,用lambda重写所有内容又有什么意义呢?为什么甚至应该尝试通过使用这样的混合体来摆脱复杂框架中的每个循环?
Tobias Liefke '18 -10-18

您的代码中有1000个带有特定用法的地方。这个习惯用语是由图书馆或任何全局结构驱动的。您可以使用基于功能方法和lambda的新结构替换该全局结构。您可以在1000个位置中的998个完全转换为实用样式。其余2个极难正确转换。在这种情况下,我总是要求使用这种混合结构将其转换为新样式。只有这样,您才能摆脱代码中的所有旧全局结构。虽然不够完美,但总体代码质量却有所提高。
德克·希尔布雷希特(Birk Hillbrecht)'18年

2

您可以导入org.omg.CORBA包(或仅导入所需的类),并且可以在其中使用Holder类。

例如,它具有“ IntHolder”,其中存储整数的字段是公共的,从而可以修改它。

public static void triple(IntHolder x){
    x.value = 3 * x.value;
}

IntHolder mutableInt = new IntHolder(10);
triple(mutableInt);     
System.out.println(mutableInt.value);

它还具有“ LongHolder”和“ DoubleHolder”以及您可以使用的许多其他功能。请谨慎使用。

这是它的api:https : //docs.oracle.com/javase/7/docs/api/org/omg/CORBA/package-summary.html


2
虽然这是解决问题的非常聪明的方法,但是随着Java9的出现,您可能不想使用它,而这只会为一个int持有者导入整个CORBA模块。
Agoston Horvath
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.