Java 不可变类的示例
我已经知道不可变类的定义,但是我需要一些例子 构建后无法更改不可变类。因此,例如,JavaJava 不可变类的示例,java,immutability,Java,Immutability,我已经知道不可变类的定义,但是我需要一些例子 构建后无法更改不可变类。因此,例如,Java字符串是不可变的 要使类不可变,必须使其final和所有字段private和final。例如,以下类是不可变的: public final class Person { private final String name; private final int age; private final Collection<String> friends;
字符串是不可变的
要使类不可变,必须使其final
和所有字段private
和final
。例如,以下类是不可变的:
public final class Person {
private final String name;
private final int age;
private final Collection<String> friends;
public Person(String name, int age, Collection<String> friends) {
this.name = name;
this.age = age;
this.friends = new ArrayList(friends);
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
public Collection<String> getFriends() {
return Collections.unmodifiableCollection(this.friends);
}
}
公共最终课程人员{
私有最终字符串名;
私人最终年龄;
私人最终收藏朋友;
公众人物(字符串名称、整数、收藏朋友){
this.name=名称;
这个。年龄=年龄;
this.friends=新阵列列表(friends);
}
公共字符串getName(){
返回此.name;
}
公共整数getAge(){
返回这个年龄;
}
公共集合getFriends(){
返回集合。不可修改集合(this.friends);
}
}
我在代码示例中添加了一个方法,展示了如何处理集合,这一点很重要
在可能的情况下,您应该使类不可变,因为这样您就不必担心线程安全之类的问题。String
是不可变类的一个很好的“现实世界”示例。您可以将其与可变StringBuilder
类进行对比
大多数用于反射的Java类都是不可变的。还有一些是“几乎不可变的”:例如,实现Accessible
的类只有一个setAccessible
方法,可以更改Accessible
实例的状态
我相信标准类库中还有很多内容。Sun(Oracle)文档中有一个关于如何创建不可变对象的优秀清单
不要提供“setter”方法—修改字段或字段引用的对象的方法
将所有字段设置为最终字段和私有字段
不允许子类重写方法。最简单的方法是将类声明为final。一种更复杂的方法是使构造函数私有,并在工厂方法中构造实例
如果实例字段包括对可变对象的引用,则不允许更改这些对象:
- 不要提供修改可变对象的方法
- 不要共享对可变对象的引用。永远不要存储对传递给构造函数的外部可变对象的引用;如有必要,创建副本并存储对副本的引用。类似地,在必要时创建内部可变对象的副本,以避免在方法中返回原始对象
发件人:
该站点还提供了在并发上下文中使用它的示例,但在编写库时,不变性也很有用。它确保库的调用者只能更改我们允许他们更改的内容。标准API中一些著名的不可变类:
- java.lang.String(已经提到)
- 基本类型的包装器类:java.lang.Integer、java.lang.Byte、java.lang.Character、java.lang.Short、java.lang.Boolean、java.lang.Long、java.lang.Double、java.lang.Float
- java.lang.StackTraceeElement(用于生成异常stacktraces)
- 大多数枚举类是不可变的,但这实际上取决于具体情况。(不要实现可变枚举,这有时会把你搞砸。)我认为至少标准API中的所有枚举类实际上都是不可变的
- java.math.BigInteger和java.math.BigDecimal(至少这些类的对象本身、子类可能引入可变性,尽管这不是一个好主意)
- java.io.File。请注意,这表示VM外部的对象(本地系统上的文件),该对象可能存在也可能不存在,并且具有一些修改和查询此外部对象状态的方法。但是文件对象本身保持不变。(java.io中的所有其他类都是可变的。)
- java.awt.Font-表示用于在屏幕上绘制文本的字体(可能有一些可变的子类,但这肯定不会有用)
- java.awt.BasicStroke-用于在图形上下文中绘制线条的辅助对象
- java.awt.Color-(至少这个类的对象,一些子类可能是可变的,或者取决于一些外部因素(如系统颜色)),以及java.awt.Paint的大多数其他实现,如
- java.awt.GradientPaint
- java.awt.LinearGradientPaint
- java.awt.RadialGradientPaint
- (我对java.awt.TexturePaint不太确定)
- Cursor-表示鼠标光标的位图(这里也有一些子类可能是可变的或取决于外部因素)
- java.util.Locale—表示特定的地理、政治或文化区域
- java.util.UUID—尽可能多的全局唯一标识符
- 虽然大多数集合都是可变的,但java.util.collections类中有一些包装器方法,它们返回集合的不可修改视图。如果您向它们传递一个在任何地方都不知道的集合,那么这些集合实际上是不可变的集合。另外,
Collections.singletonMap()
,singletonList
,singleton
返回不可变的单元素集合,也有不可变的空集合
- java.net.URL和java.net.URI-表示资源(在internet或其他地方)
- java.net.inet4地址和java.net.inet6地址,java.net.InetSocketAddress
- java.security.Permission的大多数子类(表示某些操作所需的权限或赋予某些代码的权限),但不包括java.security.PermissionCollection和子类
- 除了
DateTimeException
之外,java.time
的所有类都是不可变的。的子包的大多数类
public static void immutableOperation(){
String str=new String("String is immutable class in Java object value cann't alter once created...");
System.out.println(str);
str.replaceAll("String", "StringBuffer");
System.out.println(str);
str.concat("Concating value ");
System.out.println(str + "HashCode Value " + str.hashCode());
str=str.concat("Concating value ");
System.out.println(str + "HashCode Val " + str.hashCode());
}
public static void mutableOperation(){
StringBuffer str=new StringBuffer("StringBuffer is mutable class in Java object value can alter once created...");
System.out.println(str + "HashCode Val - " + str.hashCode());
str.replace(0, 12, "String");
System.out.println(str + "HashCode Val - " + str.hashCode());
}
class MutableBook {
private String title;
public String getTitle(){
return this.title;
}
public void setTitle(String title){
this.title = title;
}
}
public class ImmutableReader {
private final MutableBook readersBook;
private final int page;
public ImmutableReader(MutableBook book) {
this(book, 0);
}
private ImmutableReader(MutableBook book, int page){
this.page = page;
// Make copy to ensure this books state won't change.
MutableBook bookCopy = new MutableBook();
bookCopy.setTitle(book.getTitle());
this.readersBook = bookCopy;
}
public MutableBook getBook() {
// Do not return the book, but a new copy. Do not want the readers
// book to change it's state if developer changes book after this call.
MutableBook bookCopy = new MutableBook();
bookCopy.setTitle(this.readersBook.getTitle());
return bookCopy;
}
public int getPage() {
// primitives are already immutable.
return page;
}
/**
* Must return reader instance since it's state has changed.
**/
public ImmutableReader turnPage() {
return new ImmutableReader(this.readersBook, page + 1);
}
}
private final List<String> fruitnames;
public Fruit(List<String> fruitnames) {
this.fruitnames = new ArrayList<>(fruitnames);
}
public List<String> getFruitnames() {
return new ArrayList<>(fruitnames);
}
@Override
public int hashCode() {
return getFruitnames() != null ? getFruitnames().hashCode(): 0;
}
public static void main(String args[]){
List<String> fruitList = new ArrayList<>();
fruitList.add("Apple");
fruitList.add("Banana");
//Immutable Object 1
Fruit fruit1 = new Fruit(fruitList);
//fruitHash is-689428840
int fruitHash = fruit1.hashCode();
System.out.println("fruitHash is" +fruitHash);
//This value will not be added anymore as the state has already been defined and
//now it cant change the state.
fruitList.add("straberry");
//fruitHash1 is-689428840
int fruitHash1 = fruit1.hashCode();
System.out.println("fruitHash1 is" +fruitHash1);
}