目录
4、在 Java 中定义Immutable Objects的方式有哪些?
1、什么是Immutable Objects?
不可变对象指的是在创建之后,它们的值无法被修改的对象。这意味着如果想改变一个不可变对象的值,就需要创建一个新的对象。
在许多编程语言中,字符串和数字都是不可变的对象。例如,在 Python 中,字符串就是不可变的,因此不能像下面这样改变字符串的值:
string = "hello"
string[0] = "H" # This will raise an error
相反,你需要创建一个新的字符串对象:
new_string = "H" + string[1:]
这个新字符串就是一个全新的字符串对象,和原来的字符串对象没有关系。
不可变对象的一个好处是它们更容易被并发程序安全地使用。因为不可变对象是无法修改的,所以不需要担心在多线程环境下出现竞态条件的问题。
此外,不可变对象也更容易进行缓存和复用。因为不可变对象的值不会改变,所以你可以安全地将它们存储在缓存中,并在需要时直接使用它们,而不需要重新计算。
所以,合理的使用不可变对象可以提高程序的安全性、并发性能和效率。
2、Java 中有哪些不可变的对象?
Java中有许多不可变的对象,以下是其中的一些:
- 字符串(String):字符串在Java中是不可变的对象。一旦创建了一个字符串对象,它的值就不能被修改。
- 整数(Integer)、长整数(Long)、浮点数(Float)和双精度浮点数(Double):这些数字类型在Java中也是不可变的对象。一旦创建了一个数字对象,它的值就不能被修改。
- 枚举(Enum):枚举类型也是不可变的对象。枚举类型中的每个元素都是一个不可变的对象。
- LocalDate、LocalTime、LocalDateTime:Java 8中的日期和时间API中的这些类也是不可变的对象。一旦创建了一个日期或时间对象,它的值就不能被修改。
- BigInteger、BigDecimal:这些类提供了任意精度的整数和浮点数运算,也是不可变的对象。
需要注意的是,虽然以上对象的值不能被修改,但是它们的引用可以被修改。这意味着,可以创建新的对象来代替旧的对象,但是旧的对象本身的值不会被修改。
3、不可变对象在JVM中的存储
Java中不可变对象通常存在JVM的方法区(Method Area)或者叫做永久代(PermGen)中。方法区是JVM中的一块内存区域,用于存储类的信息、静态变量、常量池、方法代码等。永久代是方法区的一个实现,用于存储静态文件、类文件信息、字节码、常量池等内容,它在Java 8之后被元空间(Metaspace)所取代。// 存储在方法区中的常量池里
不可变对象通常在JVM启动时被加载并存储在方法区或永久代中,因为它们的值是不可变的,所以可以被安全地共享和重用。同时,这些对象在JVM生命周期内只需要被创建一次,因此它们的存储位置也通常是固定的。
需要注意的是,如果使用字符串常量或常量表达式创建不可变对象,这些对象也可能存储在JVM的常量池中。常量池是方法区的一部分,用于存储字符串常量、基本类型常量等。由于常量池中的字符串常量是不可变的,因此它们也被认为是不可变对象。
4、在 Java 中定义Immutable Objects的方式有哪些?
在 Java 中,有多种方式可以定义不可变对象。以下是几种常见的方式:
- 声明类为 final:通过将类声明为 final 类型,可以确保该类不能被继承和修改。这样可以确保不会发生对象状态的改变。例如:// 不允许子类重写方法。最简单的就是将类声明为final。
public final class ImmutableClass {
// ...
}
- 将所有字段设置为 final 和 private:通过将类的成员变量声明为 final,可以确保这些变量在对象创建后不能被修改。例如:
public final class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
- 不提供 setter 方法:通过只提供 getter 方法,而不提供 setter 方法,可以确保对象的状态不能被修改。例如:
public final class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
- 构造对象时赋值:通过在构造函数中初始化对象的成员变量,可以确保对象创建后它们的值不会改变。示例同上。
- 使用不可变集合类:Java 中的 Collections 类提供了一些不可变的集合类,如 Collections.unmodifiableList 和 Collections.unmodifiableMap,它们可以确保集合内容在对象创建后不能被修改。例如:
List<String> list = new ArrayList<>();
list.add("foo");
list.add("bar");
List<String> immutableList = Collections.unmodifiableList(list);
以上是一些在 Java 中定义不可变对象的方式,这些方式可以单独使用,也可以结合使用,以创建更加严格的不可变对象。// 在并发程序中作为锁的对象应该是不可变对象。