Java不可变类?

我找到了一篇包含一段有趣代码的文章 :

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); } } 

我非常好奇理解创建这种类的优势。 我知道这个类的对象是不可变的,因为初始化后无法更改其变量值。 我之前从未做过这样的事情,我真的不明白它的优点。

  • 为什么这是一个好习惯?
  • 你能说出一种可以使用这种方法的情况吗?
  • 常量或只读变量怎么样? 那不是很相似吗?
  • 在文章中说,这对应用程序的性能不利。 但为什么呢?

你提到的例子是一个不可变对象 。 它在编程语言中被广泛使用的概念。

引用上面的链接。 优点是

  • 很容易构建,测试和使用
  • 是自动线程安全的,没有同步问题
  • 不需要复制构造函数
  • 不需要克隆的实现
  • 允许hashCode使用延迟初始化,并缓存其返回值
  • 当用作场时,不需要防御性地复制
  • 制作好的Map键和Set元素(这些对象在集合中不得改变状态)
  • 他们的class级不变建立一次,它永远不需要再次检查
  • 总是有“失败primefaces性”(Joshua Bloch使用的术语):如果一个不可变对象 – 引发exception,它永远不会处于不受欢迎或不确定的状态

不可变类是:

  • 默认情况下是线程安全的(并发写不会发生)
  • 可缓存

您可以在Effective Java中使用Java语言的文本中阅读很多相关内容。

– 为什么这是一个好习惯?

因为你可以传递这个类,并确保它永远不会被“流氓”代码修改。 Java Strings也是如此,它们是不可变的。

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

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

– 关于常量或只读变量的内容? 那不是很相似吗?

不是Java,因为我们既没有const也没有只读。 我们所拥有的只是final关键字,确保在第一次分配之后不会修改对象引用。 但即使引用不能,仍然可以修改基础对象。 不可变类确保在创建后不会更改对象状态。

– 在文章中说,这对应用程序的性能不利。 但为什么?

因为每次需要修改对象时,都需要创建新实例。 对于Strings来说,你不能做myString.append("42") ,你需要做myString = myString+"42" ,这会创建一个新的String对象。

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

文章说“创建不可变对象可以达到应用程序的性能。” 我不确定为什么会这样说。 这是完全错误的。 可变对象没有任何内在因素可能会影响应用程序的性能。

如果你正在使用hashTables,那么拥有不可变对象是好的,因为你不需要在对象状态发生变化时重新计算hashCode(因为它们是不可更改的)。

文章说:

要使类不可变,可以将其所有构造函数定义为private,然后创建一个公共静态方法来初始化和对象并返回它。

实际上,这是错误的。 这两个概念并没有真正相关。

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

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

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

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

含义:由于构造函数是私有的,所以你做不到

 Employee e = new Employee("steve","jobs"); 

来自本课程以外的课程。

通过这样做,这个类的程序员正在将这个类的对象创建带入他的控件中。

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

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

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