深入理解Java中的不可变对象

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 类,包装器类 Integer、Long 等也是不可变类。

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 Book getBook() {

return book;

}

}

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

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

最后

学习视频:

[外链图片转存中…(img-mytMAkyY-1714740302018)]

大厂面试真题:

[外链图片转存中…(img-oNfkx3L9-1714740302019)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值