Java不可变类?

Java不可变类?,java,Java,我发现了一个带有一段有趣代码的: public class Employee { private String firstName; private String lastName; //private default constructor private Employee(String firstName, String lastName) { this.firstName = firstName; this.lastNam

我发现了一个带有一段有趣代码的:

public class Employee {

    private String firstName;
    private String lastName;

    //private default constructor
    private Employee(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public static Employee valueOf (String firstName, String lastName) {
        return new Employee(firstName, lastName);
    }
}
我真的很想了解创建这种类的好处。 我知道在这里,这个类的对象是不可变的,因为一旦初始化,就无法更改它的变量值。我以前从未做过这样的事,我也不太明白这样做的好处

  • 为什么这是一个好的做法
  • 你能说出一个可以使用这种方法的情况吗
  • 常数或只读变量呢?这不是很相似吗
  • 文章中说,这对应用程序的性能不好但为什么
不可变类包括:

  • 默认情况下线程安全(从不发生并发写入)
  • 可唱

您可以在Java in语言的上下文中阅读到很多关于它们的信息。

如果您使用哈希表,拥有不可变对象是很好的,因为当对象的状态更改时(因为它们是不可更改的),您不需要重新计算哈希代码。

不可变类的主要优点是线程安全。线程的大多数问题来自于共享的、可变的状态。通过使对象不可变,更容易对其进行推理,特别是在多线程环境中


这篇文章说“创建不可变对象会影响应用程序的性能。”我不知道为什么会这样说。这是完全错误的。不可变对象没有任何固有的特性会影响应用程序的性能。

您提到的示例就是一个例子。它的概念在许多领域被广泛使用

从上面的链接引用。优点是

  • 易于构造、测试和使用
  • 是自动线程安全的,并且没有同步问题
  • 不需要复制构造函数
  • 不需要克隆的实现
  • 允许hashCode使用延迟初始化,并缓存其返回值
  • 当用作字段时,不需要防御性复制
  • 制作良好的映射键并设置元素(这些对象在集合中时不得更改状态)
  • 在构造时立即建立它们的类不变量,并且不再需要再次检查它
  • 始终具有“失败原子性”(Joshua Bloch使用的一个术语):如果一个不可变对象抛出一个异常,它永远不会处于不希望的或不确定的状态
-为什么这是一个好的做法

因为您可以传递该类,并确保它永远不会被“流氓”代码修改。Java字符串也是一样,它们是不可变的

-你能说出一个可以使用这种方法的情况吗

在许多团队协作的大型项目中,或者在设计框架或API时,它非常有用。在这些情况下,由于您不负责代码的某些部分,因此您永远不能相信传递给代码其他部分的对象不会被更改。如果需要确保对象不会被修改,请使用不变性

-常数或只读变量呢?这不是很相似吗

不是在Java中,因为我们既没有常量也没有只读。我们所拥有的只是确保对象引用在第一次赋值之后不会被修改的最后一个关键字。但是,即使引用不能修改,底层对象仍然可以修改。不可变类确保对象状态在创建后不会改变

-文章中说,这对应用程序的性能不好。但是为什么呢

因为每次需要修改对象时,都需要创建新实例。同样对于字符串,您不能执行
myString.append(“42”)
,您需要执行
myString=myString+“42”
,这将创建一个新的字符串对象。

文章说:

要使一个类不可变,您可以定义它的所有构造函数私有,然后创建一个公共静态方法来初始化、对象并返回它

事实上,这是错误的。这两个概念实际上并不相关

例如,您可以将Employee类的构造函数声明为public,但它仍然是不可变的

或者可以将可变对象作为参数传递给工厂方法或声明mutator方法


->虽然您使用的是工厂方法和私有构造函数,但Employee是可变的。

在给定的示例中,他将构造函数设置为私有的,从而直接从外部控制对象创建

意思:由于构造函数是私有的,所以您不能这样做

Employee e = new Employee("steve","jobs"); 
从这门课之外

通过这样做,这个类的程序员可以控制这个类的对象创建

这是非常有益的,当您编写非常庞大的服务器端类时,由于对象的大小,创建对象可能会占用大量内存。现在,您如何保护您的客户机不受影响,不为您的类创建更多的对象

上述问题的答案很简单,只要将构造函数设置为私有,并在需要静态方法时为类创建对象即可。 注意:可以使用类名直接访问静态方法


注意:这种设计模式将在单例设计模式中大量使用,单例设计模式对于给定的类只需要一个对象。

可变状态使得很难对代码的功能进行推理。查看函数式编程。此类没有访问器方法。这是故意的吗?如果你还没有读过这篇有用的文章:只是一个旁注:为了使这个类是不可变的,这个类必须是最终的;字段也必须是最终字段。那篇文章太糟糕了!不要听从它的建议,它的许多陈述都是完全错误的。例如,“Quote 1”是错误的:在现代JVM中,对象实例化非常快。“Quote 2”指出,将实例字段公开是不好的,然后显示了一种同样糟糕的“最佳方法”:泄漏