java 类变成不可变类_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);

}

}

我真的很好奇理解创建此类的好处。 我知道这里的此类对象是不可变的,因为一旦初始化就无法更改其变量值。 我以前从未做过这样的事情,而且我真的不了解它的优势。

为什么是个好习惯?

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

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

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

可变状态使得很难推断代码的作用。 查看函数式编程。

此类没有访问器方法。 那是故意的吗?

有用的文章,如果您还没有阅读的话:javapractices.com/topic/TopicAction.do?Id=29

附带说明:为了使该类不可变,该类必须是最终的; 这些字段也必须是最终字段。

那篇文章太糟糕了! 不要听从它的建议,它所作的许多陈述是完全错误的。 例如,"报价1"是错误的:在现代JVM中,对象实例化非常快。"报价2"指出将实例字段公开是不好的,然后显示了一种"最佳方法",这同样很糟糕:从吸气剂中泄漏出可变对象(工作日数组)。 啊。 我认为该文章中的每个观点至少都有一件事是错的。

您提到的示例是不可变对象。它在编程语言中得到了广泛使用的概念。

从上面的链接报价。优点是

易于构建,测试和使用

自动是线程安全的,并且没有同步问题

不需要复制构造函数

不需要克隆的实现

允许hashCode使用延迟初始化,并缓存其返回值

用作字段时不需要防御性地复制

制作好Map键和Set元素(这些对象在集合中时不得更改状态)

在构造时就建立了其类不变式,因此无需再次检查

总是具有"失败原子性"(约书亚·布洛赫(Joshua Bloch)使用的术语):如果一个不可变的对象-引发异常,则它永远不会处于不希望的状态或不确定的状态

做好列出优势的工作。我只想补充一句,通常不需要以不变的方式实现员工类,因为那时不需要上述任何要点,但是共享的可变状态可以更轻松地使员工的所有视图保持一致,即对员工的任何修改都会引用它的每个人都可以立即看到。如果我们必须创建一个新对象来表示更改后的状态,则旧引用仍会看到旧状态。有时这是所希望的,有时是不希望的,并且更新所有引用以指向新对象是低效且麻烦的。

我不确定"允许hashCode使用延迟初始化并缓存其返回值"。您是说在第一次调用对象的hashCode()方法时计算对象哈希码并将其存储在字段中,然后将该字段返回吗?因为在那种情况下,该对象实际上是不可变的,并且失去了"自动线程安全"属性。多个线程不能同时安全地调用hashCode(),除非它们可以确定该字段先前已初始化(或者除非使用synchronized / volatile / whatnot)。

@Ruakh:是的。我相信即使在那种情况下,也有办法使它成为多线程安全的-例如,如果您可以自动确定尚未计算出哈希码,然后在初始化哈希码的同时计算并返回正确的值,那么您知道对于本地执行线程,正确的值始终是返回的值。您可能会两次计算该值,但我认为您仍将始终获得正确的值。我希望我能方便地使用" Java Concurrency in Practice",以便我可以查找详细信息(并确保Im正确)。

@jprete:当然有很多方法,但是它们需要明确的动作;它与真正不变的对象所提供的" automatic []线程安全[ty]"完全不同。

@jprete:无法自动确定是否未计算哈希码,如果没有,则无法进行计算。正如ruakh所暗示的那样,如果对象最初确实是不可变的,则没有理由不能在构造函数中计算哈希码。

不变类是:

默认情况下是线程安全的(永远不会发生并发写入)

可骑

您可以在《有效Java》中Java语言的扩展中阅读很多有关它们的信息。

equality check can be done with ==不正确。

仅仅因为类是不可变的,并不意味着可以使用" =="来检查相等性。例如,字符串是不可变的,并且在许多情况下," =="将不起作用,而.equals()会起作用。为了使它起作用,需要将其与扩展工厂结合使用,以确保"相等"值的实例不超过一个。

好的,我删除了它,但是如果我对类拥有完全的实例控制,则可以将它们与==进行比较,这意味着ziesemer编写了什么。

并发写入将如何发生?该示例未提供创建对象后回写对象的任何方法。

-Why is it a good practice?

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

-Could you name a situation where this approach can be used?

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

-What about constants or read only variables? Is not that very similar?

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

-In the article says, that this is not good for the performance of the application. But why?

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

除了关于性能的评论外,我几乎投票赞成,因为它们是错误的。是的,使用不可变的对象意味着您要分配更多的对象,但是在现代JVM实现中,这应该很快。

是的,分配并不是那么昂贵,但是new运算符不仅分配一个对象,它还调用构造函数。在上面的示例中,字符串串联涉及复制整个字符串的内容,这对于大型或频繁复制的字符串可能会变得昂贵。

分配不可变对象的新副本的成本部分(或完全!)由以下事实弥补:您不再需要制作防御性副本。我的经验是,有价值对象的防御性复制比修改要频繁得多,因此,如果对象是不可变的,则实际上您制作的副本较少。

对于价值对象,我完全同意-但Employee不是价值对象。

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

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

没事吗创建新对象并复制其整个状态,与更新单个字段一样快吗?

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

文章说:

To make a class immutable you can define its all constructors private and then create a public static method to initialize and object and return it.

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

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

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

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

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

含义:由于构造函数是私有的,因此您不能做

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

从此类之外。

这样,此类的程序员将针对该类的对象创建带入他的控件中。

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

上面的问题的答案很简单,只需将构造函数设为私有,就可以在需要使用静态方法时为类创建对象。

注意:静态方法可以通过使用类名直接访问。

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值