如何在Java中创建不可变的类

一个不可变类是指其状态一旦创建不能改变。有某些准则可以创建Java中不可变的类

在这篇文章中,我们将重新审视这些准则。

目录

1.创建不可变类的规则
2。 Java不可变类示例
3.使类不可变的好处
5.总结

1.创建不可变类的规则

Java文档本身具有一些准则,可以确定在此链接中编写不可变的类。通过创建带有可变对象和Date字段的不可变类,我们将理解这些准则的实际含义。

  1. 不要提供“设置”方法-修改字段或字段引用的对象的方法。

    该原则表明,对于您的类中的所有可变属性,请勿提供setter方法。Setter方法用于更改对象的状态,这是我们在此要避免的。

  2. 将所有字段定为最终私有

    这是增加不变性的另一种方法。声明为私有的字段将无法在班级以外访问,并且使它们成为最终字段将确保您即使不小心也无法更改它们。

  3. 不允许子类覆盖方法

    最简单的方法是将类声明为final。Java中的最终类不能被覆盖。

  4. 具有可变实例变量时要特别注意

    永远记住,您的实例变量将是可变的不可变的。标识它们并返回具有所有可变对象复制内容的新对象。不变的变量可以安全地返回而无需额外的努力。

    一种更复杂的方法是使构造函数私有化,并以工厂方法构造实例。

2。 Java不可变类示例

让我们将以上所有规则应用于不可变类,并为Java中的不可变类制定具体的类实现。

import java.util.Date;

/**
* Always remember that your instance variables will be either mutable or immutable.
* Identify them and return new objects with copied content for all mutable objects.
* Immutable variables can be returned safely without extra effort.
* */
public final class ImmutableClass
{

	/**
	* Integer class is immutable as it does not provide any setter to change its content
	* */
	private final Integer immutableField1;

	/**
	* String class is immutable as it also does not provide setter to change its content
	* */
	private final String immutableField2;

	/**
	* Date class is mutable as it provide setters to change various date/time parts
	* */
	private final Date mutableField;

	//Default private constructor will ensure no unplanned construction of class
	private ImmutableClass(Integer fld1, String fld2, Date date)
	{
		this.immutableField1 = fld1;
		this.immutableField2 = fld2;
		this.mutableField = new Date(date.getTime());
	}

	//Factory method to store object creation logic in single place
	public static ImmutableClass createNewInstance(Integer fld1, String fld2, Date date)
	{
		return new ImmutableClass(fld1, fld2, date);
	}

	//Provide no setter methods

	/**
	* Integer class is immutable so we can return the instance variable as it is
	* */
	public Integer getImmutableField1() {
		return immutableField1;
	}

	/**
	* String class is also immutable so we can return the instance variable as it is
	* */
	public String getImmutableField2() {
		return immutableField2;
	}

	/**
	* Date class is mutable so we need a little care here.
	* We should not return the reference of original instance variable.
	* Instead a new Date object, with content copied to it, should be returned.
	* */
	public Date getMutableField() {
		return new Date(mutableField.getTime());
	}

	@Override
	public String toString() {
		return immutableField1 +" - "+ immutableField2 +" - "+ mutableField;
	}
}

现在该测试我们的课程了:

class TestMain
{
	public static void main(String[] args)
	{
		ImmutableClass im = ImmutableClass.createNewInstance(100,"test", new Date());
		System.out.println(im);
		tryModification(im.getImmutableField1(),im.getImmutableField2(),im.getMutableField());
		System.out.println(im);
	}

	private static void tryModification(Integer immutableField1, String immutableField2, Date mutableField)
	{
		immutableField1 = 10000;
		immutableField2 = "test changed";
		mutableField.setDate(10);
	}
}

程序输出:

100 - test - Tue Oct 30 21:34:08 IST 2012
100 - test - Tue Oct 30 21:34:08 IST 2012

可以看出,即使使用其引用更改实例变量也不会更改其值,因此该类是不可变的。

JDK中的不可变类

除了您编写的类,JDK本身还有很多不可变的类。给出了这样的Java不可变类的列表。

  1. Wrapper 类,例如Integer,Long,Double等。
  2. 不可变的集合类,例如Collections.singletonMap()等。
  3. java.lang.StackTraceElement
  4. Java枚举(理想情况下应该如此)
  5. java.util.Locale
  6. java.util.UUID

3.使类不可变的好处

首先让我们确定不可变类的优点。在Java中,不可变类为:

  1. 易于构建,测试和使用
  2. 自动是线程安全的,并且没有同步问题
  3. 不需要复制构造函数
  4. 不需要克隆的实现
  5. 允许hashCode()使用延迟初始化,并缓存其返回值
  6. 用作字段时不需要防御性地复制
  7. 制作好Map键和Set元素(这些对象在集合中时不得更改状态)
  8. 在构造时就建立了其类不变式,因此无需再次检查
  9. 总是具有“ 失败原子性 ”(约书亚·布洛赫(Joshua Bloch)使用的术语):如果不可变对象抛出异常,则永远不会处于不希望或不确定的状态

4.总结

在本教程中,我们学习了使用可变对象以及不可变字段创建不可变的Java类。我们还看到了不可变类在应用程序中带来的好处。

作为最佳设计实践,始终旨在使您的应用程序Java类不可变。这样,您始终可以更少担心程序中与并发相关的缺陷。

如何编写一个不变的类?这也可能是一个面试问题

阅读更多:

为什么字符串类在Java中是不可变的?

saigon has written 1445 articles

Leave a Reply