iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >如何创建Java的不可变对象
  • 383
分享到

如何创建Java的不可变对象

2023-06-25 14:06:20 383人浏览 八月长安
摘要

如何创建Java的不可变对象,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。前言:为什么 String 是 immutable 类(不可变对象)吗?我想研究它,想

如何创建Java的不可变对象,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

    前言:

    为什么 String immutable 类(不可变对象)吗?我想研究它,想知道为什么它就不可变了,这种强烈的愿望就像想研究浩瀚的星空一样。但无奈自身功力有限,始终觉得雾里看花终隔一层。二哥你的文章总是充满趣味性,我想一定能够说明白,我也一定能够看明白,能在接下来写一写吗?

    https://GitHub.com/itwanger/toBeBetterJavaer

    01、什么是不可变类

    一个类的对象在通过构造方法创建后如果状态不会再被改变,那么它就是一个不可变(immutable)类。它的所有成员变量的赋值仅在构造方法中完成,不会提供任何 setter 方法供外部类去修改。

    还记得《神雕侠侣》中小龙女的古墓吗?随着那一声巨响,仅有的通道就被无情地关闭了。别较真那个密道,我这么说只是为了打开你的想象力,让你对不可变类有一个更直观的印象。

    自从有了多线程,生产力就被无限地放大了,所有的程序员都爱它,因为强大的硬件能力被充分地利用了。但与此同时,所有的程序员都对它心生忌惮,因为一不小心,多线程就会把对象的状态变得混乱不堪。

    为了保护状态的原子性、可见性、有序性,我们程序员可以说是竭尽所能。其中,synchronized(同步)关键字是最简单最入门的一种解决方案。

    假如说类是不可变的,那么对象的状态就也是不可变的。这样的话,每次修改对象的状态,就会产生一个新的对象供不同的线程使用,我们程序员就不必再担心并发问题了。

    02、常见的不可变类

    提到不可变类,几乎所有的程序员第一个想到的,就是 String 类。那为什么 String 类要被设计成不可变的呢?

    1)常量池的需要

    字符串常量池是 Java 堆内存中一个特殊的存储区域,当创建一个 String 对象时,假如此字符串在常量池中不存在,那么就创建一个;假如已经存,就不会再创建了,而是直接引用已经存在的对象。这样做能够减少 JVM 的内存开销,提高效率。

    2)hashCode 的需要

    因为字符串是不可变的,所以在它创建的时候,其 hashCode 就被缓存了,因此非常适合作为哈希值(比如说作为 HashMap 的键),多次调用只返回同一个值,来提高效率。

    3)线程安全

    就像之前说的那样,如果对象的状态是可变的,那么在多线程环境下,就很容易造成不可预期的结果。而 String 是不可变的,就可以在多个线程之间共享,不需要同步处理。

    因此,当我们调用 String 类的任何方法(比如说 trim()substring()toLowerCase())时,总会返回一个新的对象,而不影响之前的值。

    String cmower = "沉默王二,一枚有趣的程序员"; cmower.substring(0,4); System.out.println(cmower);// 沉默王二,一枚有趣的程序员

    虽然调用 substring() 方法对 cmower 进行了截取,但 cmower 的值没有改变。

    除了 String 类,包装器类 IntegerLong 等也是不可变类。

    03、手撸不可变类

    看懂一个不可变类也许容易,但要创建一个自定义的不可变类恐怕就有点难了。但知难而进是我们作为一名优秀的程序员不可或缺的品质,正因为不容易,我们才能真正地掌握它。

    接下来,就请和我一起,来自定义一个不可变类吧。一个不可变诶,必须要满足以下 4 个条件:

    • 1)确保类是 final 的,不允许被其他类继承。

    • 2)确保所有的成员变量(字段)是 final 的,这样的话,它们就只能在构造方法中初始化值,并且不会在随后被修改。

    • 3)不要提供任何 setter 方法。

    • 4)如果要修改类的状态,必须返回一个新的对象。

    按照以上条件,我们来自定义一个简单的不可变类 Writer

    public final class Writer {     private final String name;     private final int age;      public Writer(String name, int age) {         this.name = name;         this.age = age;     }      public int getAge() {         return age;     }      public String getName() {         return name;     } }

    Writer 类是 final 的,name age 也是 final 的,没有 setter 方法。

    OK,据说这个作者分享了很多博客,广受读者的喜爱,因此某某出版社找他写了一本书(Book)。Book 类是这样定义的:

    public class Book {     private String name;     private int price;      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      public int getPrice() {         return price;     }      public void setPrice(int price) {         this.price = price;     }      @Override     public String toString() {         return "Book{" +                 "name='" + name + '\'' +                 ", price=" + price +                 '}';     } }

    2 个字段,分别是 name price,以及 getter setter,重写后的 toString() 方法。然后,在 Writer 类中追加一个可变对象字段 book

    public final class Writer {     private final String name;     private final int age;     private final Book book;      public Writer(String name, int age, Book book) {         this.name = name;         this.age = age;         this.book = book;     }      public int getAge() {         return age;     }      public String getName() {         return name;     }      public Book getBook() {         return book;     } }

    并在构造方法中追加了 Book 参数,以及 Book getter 方法。

    完成以上工作后,我们来新建一个测试类,看看 Writer 类的状态是否真的不可变。

    public class WriterDemo {     public static void main(String[] args) {         Book book = new Book();         book.setName("WEB全栈开发进阶之路");         book.setPrice(79);          Writer writer = new Writer("沉默王二",18, book);         System.out.println("定价:" + writer.getBook());         writer.getBook().setPrice(59);         System.out.println("促销价:" + writer.getBook());     } }

    程序输出的结果如下所示:

    定价:Book{name='Web全栈开发进阶之路', price=79}
    促销价:Book{name='Web全栈开发进阶之路', price=59}

    糟糕,Writer 类的不可变性被破坏了,价格发生了变化。为了解决这个问题,我们需要为不可变类的定义规则追加一条内容:

    如果一个不可变类中包含了可变类的对象,那么就需要确保返回的是可变对象的副本。也就是说,Writer 类中的 getBook() 方法应该修改为:

    public Book getBook() {     Book clone = new Book();     clone.setPrice(this.book.getPrice());     clone.setName(this.book.getName());     return clone; }

    这样的话,构造方法初始化后的 Book 对象就不会再被修改了。此时,运行 WriterDemo,就会发现价格不再发生变化了。

    定价:Book{name='Web全栈开发进阶之路', price=79}
    促销价:Book{name='Web全栈开发进阶之路', price=79}

    04、总结

    不可变类有很多优点,就像之前提到的 String 类那样,尤其是在多线程环境下,它非常的安全。尽管每次修改都会创建一个新的对象,增加了内存的消耗,但这个缺点相比它带来的优点,显然是微不足道的——无非就是捡了西瓜,丢了芝麻。

    看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注编程网精选频道,感谢您对编程网的支持。

    --结束END--

    本文标题: 如何创建Java的不可变对象

    本文链接: https://www.lsjlt.com/news/305269.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • 如何创建Java的不可变对象
      如何创建Java的不可变对象,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。前言:为什么 String 是 immutable 类(不可变对象)吗我想研究它,想知...
      99+
      2023-06-25
    • 创建一个Java的不可变对象
      目录01、什么是不可变类02、常见的不可变类1)常量池的需要2)hashCode 的需要3)线程安全03、手撸不可变类04、总结前言: 为什么 String 是 immutable ...
      99+
      2024-04-02
    • 可变对象与不可变对象
      可变对象:   对象进行操作后,该对象内部是发生变化的   可以这样认为,操作直接作用于该对象,并使该对象发生了变化   比如list,对list进行操作,list内部的内容是会变化的   不可变对象:   对象进行操作后,该对象内部是不...
      99+
      2023-01-31
      对象
    • Python中的可变对象和不可变对象
      什么是可变/不可变对象 不可变对象,该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。 可变对象,该对象所指向的内存中的...
      99+
      2023-01-30
      对象 Python
    • python可变对象,不可变对象详解
      在写python程序时,对于可变对象和不可变对象这里理解不深,导致总会犯一些细节错误。以下面的程序举例: ab = {'a':1, 'b':2} list1 = [] for i...
      99+
      2024-04-02
    • java如何创建date对象
      Java中可以使用以下几种方法来创建Date对象:1. 使用无参构造函数创建一个表示当前日期和时间的Date对象:```javaDa...
      99+
      2023-09-13
      java
    • python可变对象和不可变对象的解释
      数据类型分为可变、不可变。可变对象表示可以原处修改该数据对象,不可变对象表示必须创建新对象来保存修改后的数据。 在基础数据类型中: 数值、字符串、元组、frozenset是不可变对象 列表、set、dict是可变对象 对于可变对象,...
      99+
      2023-01-30
      对象 python
    • java String如何被设计成不可变对象
      这篇文章主要介绍“java String如何被设计成不可变对象”,在日常操作中,相信很多人在java String如何被设计成不可变对象问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java String如何...
      99+
      2023-06-19
    • java的math类不能创建对象如何解决
      在Java中,Math类是一个工具类,其中的方法都是静态方法,因此不能通过创建对象来使用。要使用Math类提供的方法,只需要直接使用...
      99+
      2023-09-23
      java
    • 在Java中如何避免创建不必要的对象
      目录简介1、String和Boolean2、自动拆箱和装箱3、正则表达式总结简介 在Java开发中,程序员要尽可能的避免创建相同的功能的对象,因为这样既消耗内存,又影响程序运行速度...
      99+
      2024-04-02
    • Python 的可变和不可变对象详情
      目录Python 中的可变和不可变对象一、文字描述可变和不可变对象1、可变与不可变对象归类2、可变与可变对象的区别3、不可变对象的应用场景二、代码角度区别1、不可变对象-整型2、不可...
      99+
      2024-04-02
    • ActiveX不能创建对象如何解决
      如果 ActiveX 无法创建对象,可能存在以下几种可能的解决方法:1. 检查 ActiveX 控件是否正确安装:确保所需的 Act...
      99+
      2023-09-13
      ActiveX
    • python如何创建可变变量
      这篇文章主要介绍了python如何创建可变变量,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1、可以使用字典来完成此操作。字典是键和值的存储。>>>&nbs...
      99+
      2023-06-20
    • JAVA对象创建与对象克隆
      目录一、对象的4种创建方式二、通过new创建对象三、反射四、克隆对象浅拷贝深拷贝五、反序列化六、补充一、对象的4种创建方式 new 创建反射克隆反序列化 二、通过new创建对象 一般...
      99+
      2024-04-02
    • 如何在Bash中创建Java的Path对象?
      在Bash中创建Java的Path对象可能是Java开发人员经常需要处理的任务之一。Path对象是Java中表示文件路径的一种方式,而Bash则是一种常用的Unix shell。 在Bash中创建Java的Path对象,我们需要使用Java...
      99+
      2023-09-21
      path 对象 bash
    • 如何创建CLR对象
      这篇文章主要介绍了如何创建CLR对象,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一 创建CLR对象在解决方案中添加新的C#SQL数据库项目,命名为“ServiceClien...
      99+
      2023-06-17
    • 如何创建js对象
      这篇文章主要为大家展示了“如何创建js对象”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何创建js对象”这篇文章吧。1.对象字面量创建对象var obj = ...
      99+
      2024-04-02
    • JavaScript可以创建对象吗
      这篇“JavaScript可以创建对象吗”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Ja...
      99+
      2024-04-02
    • 如何创建ADO.NET对象
      这篇文章主要介绍“如何创建ADO.NET对象”,在日常操作中,相信很多人在如何创建ADO.NET对象问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何创建ADO.NET对象”的疑惑有所帮助!接下来,请跟着小编...
      99+
      2023-06-17
    • 如何在java中创建一个对象
      这篇文章给大家介绍如何在java中创建一个对象,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序。1、创建对...
      99+
      2023-06-14
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作