简体   繁体   English

可变或不可变的类?

[英]Mutable or immutable class?

I had read in some design book that immutable class improves scalability and its good practice to write immutable class wherever possible. 我在一些设计书中读到,不可变类提高了可伸缩性,并且尽可能地编写不可变类。 But I think so immutable class increase object proliferation. 但我认为如此不可改变的阶级会增加对象的扩散。 So is it good of going immutable class or better go for static class (A class with all the methods static) for improve scalability ? 因此,为了提高可伸缩性,使用静态类(具有所有静态方法的类)更好地进行不可变类或更好吗?

The main benefit of immutable classes however is that you can expose internal data members that are immutable because the caller can't modify them. 但是, 不可变类的主要好处是可以公开不可变的内部数据成员,因为调用者无法修改它们。 This is a huge problem with, say, java.util.Date . 这是一个巨大的问题,比如java.util.Date It's mutable so you can't return it directly from a method. 它是可变的,因此您无法直接从方法返回它。 This means you end up doing all sorts of defensive copying . 这意味着你最终会做各种防御性复制 That increases object proliferation. 这增加了对象的扩散。

The other major benefit is that immutable objects do not have synchronization issues, by definition. 另一个主要好处是根据定义,不可变对象没有同步问题。 That's where the scalability issues come in. Writing multithreaded code is hard. 这就是可扩展性问题的来源。编写多线程代码很难。 Immutable objects are a good way of (mostly) circumventing the problem. 不可变对象是(大多数)绕过问题的好方法。

As for "static classes", by your comment I take it to mean classes with factory methods , which is how it's usually described. 至于“静态类”,通过你的评论,我认为它是指具有工厂方法的类,这是通常描述的方式。 That's an unrelated pattern. 那是一种无关的模式。 Both mutable and immutable classes can either have public constructors or private constructors with static factory methods. 可变类和不可变类都可以具有公共构造函数或具有静态工厂方法的私有构造函数。 That has no impact on the (im)mutability of the class since a mutable class is one whose state can be changed after creation whereas an immutable class's state cannot be changed after instantiation. 这对类的(im)可变性没有影响,因为可变类是在创建后可以更改其状态的类,而在实例化后不能更改不可变类的状态。

Static factory methods can have other benefits however. 然而,静态工厂方法可以具有其他好处。 The idea is to encapsulate object creation. 想法是封装对象创建。

Immutable classes do promote object proliferation, but if you want safety, mutable objects will promote more object proliferation because you have to return copies rather than the original to prevent the user from changing the object you return. 不可变类确实会促进对象扩散,但是如果你想要安全,可变对象会促进更多的对象扩散,因为你必须返回副本而不是原始副本以防止用户更改你返回的对象。

As for using classes with all static methods, that's not really an option in most cases where immutability could be used. 至于使用所有静态方法的类,在大多数可以使用不变性的情况下,这不是一个真正的选项。 Take this example from an RPG: 从RPG中获取此示例:

public class Weapon
{
    final private int attackBonus;
    final private int accuracyBonus;
    final private int range;

    public Weapon(int attackBonus, int accuracyBonus, int range)
    {
        this.attackBonus = attackBonus;
        this.accuracyBonus = accuracyBonus;
        this.range = range;
    }

    public int getAttackBonus() { return this.attackBonus; }
    public int getAccuracyBonus() { return this.accuracyBonus; }
    public int getRange() { return this.range; }
}

How exactly would you implement this with a class that contains only static methods? 您如何使用仅包含静态方法的类实现此操作?

As cletus said, immutable classes simplify class design and handling in synchronized methods. 正如cletus所说,不可变类简化了同步方法中的类设计和处理。

They also simplify handling in collections, even in single-threaded applications. 即使在单线程应用程序中,它们也简化了集合中的处理。 An immutable class will never change, so the key and hashcode won't change, so you won't screw up your collections. 不可变类永远不会改变,因此键和哈希码不会改变,所以你不会搞砸你的收藏。

But you should keep in mind the lifecycle of the thing you're modeling and the "weight" of the constructor. 但是你应该记住你正在建模的东西的生命周期和构造函数的“重量”。 If you need to change the thing, immutable objects become more complex to deal with. 如果您需要更改该东西,则不可变对象变得更加复杂。 You have to replace them, rather than modify them. 您必须替换它们,而不是修改它们。 Not terrible, but worth considering. 并不可怕,但值得考虑。 And if the constructor takes nontrivial time, that's a factor too. 如果构造函数需要非常重要的时间,那也是一个因素。

One thing to consider: If you intend to use instances of a class as keys in a HashMap, or if you're going to put them in a HashSet, it's safer to make them immutable. 需要考虑的一件事是:如果您打算将类的实例用作HashMap中的键,或者如果您要将它们放在HashSet中,那么使它们成为不可变的更安全。

HashMap and HashSet count on the fact that the hash code for an object remains constant as long as the object is in the map or set. HashMap和HashSet指的是只要对象在map或set中,对象的哈希码就保持不变。 If you use an object as a key in a HashMap, or if you put it in a HashSet, and then change the state of the object so that hashCode() would return a different value, then you're confusing the HashMap or HashSet and you'll get strange things; 如果你将一个对象用作HashMap中的一个键,或者你把它放在一个HashSet中,然后改变对象的状态,以便hashCode()返回一个不同的值,那么你就会混淆HashMap或HashSet,你会得到奇怪的东西; for example, when you iterate the map or set the object is there, but when you try to get it, it's as if it is not there. 例如,当您迭代地图或设置对象时,但是当您尝试获取它时,就好像它不存在一样。

This is due to how HashMap and HashSet work internally - they organize objects by hash code. 这是由于HashMap和HashSet如何在内部工作 - 它们通过哈希代码组织对象。

This article by Java concurrency guru Brian Goetz gives a good overview of the pros and cons of immutable objects. Java并发大师Brian Goetz 撰写的这篇文章很好地概述了不可变对象的优缺点。

Immutability is generally used to achieve scalability, since immutability is one of the enablers when it comes to concurrent programming in java. 不可变性通常用于实现可伸缩性,因为不可变性是Java中并发编程的推动因素之一。 So while, as you point out, there may be more objects in an "immutable" solution, it may be a necessary step to improve concurrency. 因此,正如您所指出的那样,“不可变”解决方案中可能存在更多对象,这可能是提高并发性的必要步骤。

The other, equally important use og immutability is to consume a design intention ; 另一个同样重要的用途是使用不可变性来消耗设计意图 ; whoever made an immutable class intended you to put mutable state elsewhere. 制作不可变类的人意图将其置于其他地方。 If you start mutating instances of that class, you are probably breaking the original intention of the design - and who knows what the consequences may be. 如果你开始改变那个类的实例,你可能会破坏设计的初衷 - 谁知道后果可能是什么。

Consider string objects, as an example. 以字符串对象为例。 Some languages or class libraries provide mutable strings, some don't. 有些语言或类库提供可变字符串,有些则不提供。

A system that uses immutable strings can do certain optimizations that one with mutable strings cannot. 使用不可变字符串的系统可以对具有可变字符串的系统进行某些优化。 For example, you can ensure that there is only one copy of any unique string. 例如,您可以确保只有任何唯一字符串的副本。 Since the size of the object "overhead" is generally much smaller than the size of any non-trivial string, this is a potentially massive memory savings. 由于对象“开销”的大小通常远小于任何非平凡字符串的大小,因此这可能节省大量内存。 There are other potential space savings, like interning substrings. 还有其他潜在的空间节省,如实习子串。

Besides the potential memory savings, immutable objects can improve scalability by reducing contention. 除了可能的内存节省之外,不可变对象还可以通过减少争用来提高可伸缩性。 If you have a large number of threads accessing the same data, then immutable objects don't require elaborate synchronization processes for safe access. 如果您有大量线程访问相同的数据,则不可变对象不需要精心设计的同步过程来进行安全访问。

Just one more consideration about the subject. 再考虑一下这个问题。 Using immutable object allow you to cache them and not re-create them everytime (ie Strings) it helps a lot on your application performance. 使用不可变对象允许您缓存它们而不是每次都重新创建它们(即字符串)它对您的应用程序性能有很大帮助。

I think, if you want to share the same object among different variables, it needs to be immutable. 我想,如果你想在不同的变量之间共享同一个对象,它需要是不可变的。

For instance: 例如:

String A = "abc";
String B = "abc";

String object in Java is immutable. Java中的String对象是不可变的。 Now both A & B point to the same "abc" string. 现在A和B都指向相同的“abc”字符串。 Now 现在

A = A + "123";
System.out.println(B);

it should output: 它应该输出:

abc

Because String is immutable, A will simply point to new "abc123" string object instead of modifying the previous string object. 因为String是不可变的,所以A只会指向新的“abc123”字符串对象,而不是修改前一个字符串对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM