罪恶克星 发表于 2024-12-21 23:59:19

【Java底子面试题019】什么是Java中的不可变类?

回答重点

不可变类是指在创建后无法被修改的类。一旦对象被创建,它的全部属性都不能被更改。这种类的实例在整个生命周期内保持不变。
关键特性:


[*]声明类为final,防止子类继承
[*]类的全部字段都是private和final,确保它们在初始化后不能被更改
[*]通过构造函数初始化全部字段
[*]不提供任何修改对象状态的方法(如setter方法)
[*]如果类包含可变对象的引用,必须举行特别处理,确保这些引用在对象外部无法被修改,否则会导致不可变类的筹划失效,外部代码仍然可以通过引用修改对象的内部状态,破坏不可变性。例如getter方法种返回对象的副本(new一个新的对象)来掩护可变对象

扩展知识 

固然照旧能用反射获取与修改,关于反射可以看这一篇博客
【Java】反射_反射 博客园-CSDN博客
Java中的经典不可变类有:String、Integer、BigDecimal、LocalDate等
这个例子,表明如果类包含可变对象的引用,要确保这些引用在对象外部无法被修改
public class FinalTest {
    public static void main(String[] args) {
      List<String> hobbies = new ArrayList<>();
      hobbies.add("看小说");
      hobbies.add("写博客");

      Person p = new Person("AutismBtkrsr", hobbies);
      System.out.println("Name:" + p.gerName());
      System.out.println("Hobbies:" + p.getHobbies());

      List<String> list = p.getHobbies();
      list.add("玩Staem"); // 这里会抛异常 UnsupportedOperationException,因为hobbies列表是不可变的,外部无法修改它
      System.out.println("...........................");
    }
}

final class Person {
    private final String name;
    private final List<String> hobbies; // 可变对象的引用
    public Person(String name, List<String> hobbies){
      this.name = name;
      this.hobbies = new ArrayList<>(hobbies); // 这里创建了一个新的不可变列表(深拷贝),外部无法修改hobbies列表
    }
    public String gerName(){
      return this.name;
    }
    public List<String> getHobbies(){
      return Collections.unmodifiableList(this.hobbies);// 返回一个不可变的列表视图,外部无法修改hobbies列表
    }
} 不可变类的优缺点

优点:


[*]线程安全:由于不可变对象状态不能被修改,他们天生是线程安全的,在并发情况中无需同步
[*]缓存友好:不可变对象可以安全地被缓存和共享,如String的字符串常量池
[*]防止状态不一致:不可变类可以有用避免因不测修改对象状态而导致的不一致题目
缺点:


[*]性能题目:不可变对象需要在每次状态变革时创建新的对象,这会导致性能开销,尤其是对于大规模对象或频繁修改的场景(例如String频繁拼接)
举例String

String 就是典范的不可变类,当你创建一个 String 对象之后,这个对象就无法被修改。
由于无法被修改,所以像执行s+="a";这样的方法,实在返回的是一个新建的 String 对象,老的s 指向的对象不会发生变革,
只是s的引用指向了新的对象而已。
所以不要在字符串拼接频繁的场景利用+来拼接,由于这样会频繁的创建对象。
不可变类的好处就是安全,由于知晓这个对象不可能会被修改,因此可以放心大胆的用,在多线程情况下也是线程安全的。

final关键字

final 保证引用变量的地址(即内存指针)在初始化后不可再指向其他对象,final 修饰的字段只保证引用(内存地址)本身不可变,但引用指向的对象内容是可以改变的

实现一个不可变类

看一下String的筹划
https://i-blog.csdnimg.cn/direct/3bd345a643c2455882c35a9d422307b1.png
String本质是一个char数组,然后用final修饰,不外final限制不了数组内部的数据,所以这还不够。
value字段是用private修饰的,并没有暴暴露set方法,这样外部实在就打仗不到value所以无法修改。
如果还有修改的需求,比如replace()方法,所以这时间就需要返回一个新对象来作为结果
https://i-blog.csdnimg.cn/direct/7036c8e62918447fa55108066b306de7.png

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【Java底子面试题019】什么是Java中的不可变类?