当前位置: 首页 > 知识库问答 >
问题:

使Java对象不可变

边意
2023-03-14

我的目标是让Java对象不可变。我有一个班级< code >学生。为了实现不变性,我用以下方式对它进行了编码:

public final class Student {

private String name;
private String age;

public Student(String name, String age) {
    this.name = name;
    this.age = age;
}

public String getName() {
    return name;
}

public String getAge() {
    return age;
}

}

我的问题是,实现学生班级不变性的最佳方法是什么?

共有3个答案

屠锐
2023-03-14

如何使可变对象不可变?

    < li >将该类声明为final,这样它就不能被扩展。 < li >将所有字段设为私有,以便不允许直接访问。 < li >不要为变量提供setter方法 < li >将所有可变字段设为final,以便其值只能赋值一次。 < li >通过执行深度复制的构造函数初始化所有字段。 < li >在getter方法中执行对象克隆以返回副本,而不是返回实际的对象引用。

来源

我们为什么要创建不可变的对象?
不可变对象只是其状态(对象的数据)在构造后无法更改的对象。

    < li >安全性:存储敏感信息,如用户名、密码、连接URL、网络连接等。 < li >易于构建、测试和使用 < li >自动线程安全,没有同步问题 < li >不需要复制构造函数 < li >不需要克隆的实现 < li >允许hashCode使用延迟初始化,并缓存其返回值 < li >用作字段时不需要进行防御性复制 < li >制作好映射键和集合元素(这些对象在集合中不能改变状态) < li >一旦构造,就建立它们的类不变量,并且永远不需要再次检查它 < li >始终保持“失败原子性”(Joshua Bloch使用的一个术语):如果一个不可变的对象抛出异常,它绝不会处于不希望的或不确定的状态

来源

在Java中,字符串是不可变的,它提供了诸如缓存,安全性,无需复制即可轻松重用等功能。源

范瀚昂
2023-03-14

在创建不可变类时,您必须考虑一些事情:

    < li >完成您的课程< code>final -您已经完成了 < li >使所有字段< code>private和< code>final -在您的代码中进行适当的更改 < li >不要提供任何改变实例状态的方法 < li >如果您的类中有可变字段,如< code>List或< code>Date,将它们设为< code>final是不够的。您应该从它们的< code>getters返回一个防御副本,这样它们的状态就不会因为调用方法而改变。

对于第四点,假设您的类中有一个<code>Date<code>字段,那么该字段的getter应该如下所示:

public Date getDate() {
    return new Date(this.date.getTime());
}

制作防御性副本可能会成为一个令人头疼的问题,当你的可变字段本身由一些可变字段组成时,而这些可变字段又可能包含一些其他可变字段。在这种情况下,您需要以迭代方式复制它们中的每一个。我们将可变字段的迭代副本命名为深度复制。

自己实现深度复制可能很麻烦。但是,撇开这个问题不谈,你应该再次考虑你的类设计,一旦你看到自己陷入了制作深度防御性副本的要求。

朱毅
2023-03-14

严格来说,你的类不是不可变的,它只是有效地不可变。要使其不可变,您需要使用 final

private final String name;
private final String age;

尽管这种差异看起来很微妙,但它在多线程上下文中会产生重大影响。不可变类本质上是线程安全的,有效的不可变类只有在安全发布时才是线程安全的。

 类似资料:
  • 由于这是一个热门的话题,这些天,我无法理解某些概念。请原谅,如果我听起来很愚蠢,但当我试图创建不可变对象时,我发现大多数帖子如下 null null 此测试用例失败并打印Cassandra。 如果我做错了什么让我知道。

  • 问题内容: String abc[]={“abc”}; String def[]={}; 通过更改“ def”对象,我的abc对象也被更改。在String []数组旁边有这个特性还有什么其他的Java对象有类似的特性?能解释更多吗?为了防止在更改def时更改abc,我必须执行def = abc.clone();。 问题答案: 您将对象的可变性/不可变性与引用值的复制混淆了。 在这些图中,是参考变量

  • 问题内容: 我正在努力使可变对象与不可变对象有关。使用可变对象会带来很多负面影响(例如,从方法中返回字符串数组),但是我很难理解它的负面影响。使用可变对象的最佳实践是什么?您是否应尽可能避免使用它们? 问题答案: 好吧,这有几个方面。 没有参考身份的可变对象会在奇数时间导致错误。例如,考虑使用基于值的方法的 : 当实例用作键时,实例在映射中“丢失”,因为实例和相等性基于可变值。这些值在映射之外更改

  • 问题内容: Java中不变对象的优点显而易见: 一致状态 自动线程安全 简单 您可以通过使用私有final字段和构造函数注入来支持不变性。 但是,在Java中偏爱不可变对象有哪些弊端? 即 与ORM或Web演示工具不兼容? 不灵活的设计? 实施的复杂性? 是否可以设计一个主要使用不可变对象的大规模系统(深层对象图)? 问题答案: 但是,在Java中偏爱不可变对象有哪些弊端?与ORM或Web演示工具

  • 问题内容: 代码段-1 代码段-2 我在第一个代码段中遇到了竞争。我知道这是因为我正在获得对不可变对象(类型为Integer)的锁定。 我已经写了第二个代码片段,这再次使“布尔”不变。但这有效(输出运行中不显示竞争条件)。如果我正确理解了上一个问题的解决方案,则以下是出现问题的一种可能方法 线程1锁定由指向的对象(例如A) 线程2现在试图获取由指向的对象的锁,并进入A的等待队列。 线程1进入同步块

  • 我正在使用JAXB从XSD文件创建Java对象。我正在创建不可变包装器来隐藏由JAXB生成的对象(之前我更新了JAXB对象,以实现不可变接口并将接口返回给客户机。但意识到改变自动生成的类是不好的,因此使用包装器) 目前,我正在将这些不可变的包装返回到客户端应用程序。是否有任何选项,使自动生成的类将是不可变的,并避免创建不可变包装器的额外工作。任何其他方法都是鼓励的。 谢谢