- 浏览: 101507 次
- 性别:
- 来自: 武汉
-
最新评论
-
zljerityzljerity:
<#assign ipage=page?number&g ...
freeMark全解 -
qiankai86:
...
freeMark全解
所谓不可变类,是指当创建了这个类的实例后,就不允许修改它的属性值。在JDK的基本类库中,所有基本类型的包装类,如Integer和Long类,都是不可变类,java.lang.String也是不可变类。以下代码创建了一个String对象和Integer对象,它们的值分别为“Hello”和 10,在程序代码中无法再改变这两个对象的值,因为Integer和String类没有提供修改其属性值的接口。
String s=new String("Hello");
Integer i=new Integer(10);
用户在创建自己的不可变类时,可以考虑采用以下设计模式:
1..把属性定义为private final类型。
2.不对外公开用于修改属性的setXXX()方法。
public Name(String firstname, String lastname) {
3.只对外公开用于读取属性的getXXX()方法。
4.在构造方法中初始化所有属性。
5.覆盖Object类的equals()和hashCode()方法。在equals()方法中根据对象的属性值来比较两个对象是否相等,并且保证用 equals()方法判断为相等的两个对象的hashCode()方法的返回值也相等,这可以保证这些对象能正确地放到HashMap或HashSet集合中。
如果需要的话,提供实例缓存和静态工厂方法,允许用户根据特定参数获得与之匹配的实例。
例程11-9的Name类就是不可变类,它仅仅提供了读取sex和description属性的getXXX()方法,但没有提供修改这些属性的setXXX()方法。
例程11-9 Name.java
public class Name {
private final String firstname;
private final String lastname;
this.firstname = firstname;
this.lastname = lastname;
}
public String getFirstname(){
return firstname;
}
public String getLastname(){
return lastname;
}
public boolean equals(Object o){
if (this == o) return true;
if (!(o instanceof Name)) return false;
final Name name = (Name) o;
if(!firstname.equals(name.firstname)) return false;
if(!lastname.equals(name.lastname)) return false;
return true;
}
public int hashCode(){
int result;
result= (firstname==null?0:firstname.hashCode());
result = 29 * result + (lastname==null?0:lastname.hashCode());
return result;
}
public String toString(){
return lastname+" "+firstname;
}
}
假定Person类的name属性定义为Name类型:
public class Person{
private Name name ;
private Gender gender;
…
}
以下代码创建了两个Person对象,他们的姓名都是“王小红”,一个是女性,另一个是男性。在最后一行代码中,把第一个Person对象的姓名改为“王小虹”。
Name name=new Name("小红","王");
Person person1=new Person(name,Gender.FEMALE);
Person person2=new Person(name,Gender.MALE);
name=new Name("小虹","王");
person1.setName(name); //修改名字
与不可变类对应的是可变类,可变类的实例属性是允许修改的。如果把以上例程11-9的Name类的firstname属性和lastname属性的 final修饰符去除,并且增加相应的public类型的setFirstname()和setLastname()方法,Name类就变成了可变类。以下程序代码本来的意图也是创建两个Person对象,他们的姓名都是“王小红”,接着把第一个Person对象的姓名改为“王小虹”:
//假定以下Name类是可变类
Name name=new Name("小红","王");
Person person1=new Person(name,Gender.FEMALE);
Person person2=new Person(name,Gender.MALE);
name.setFirstname(" 小虹"); //试图修改第一个Person对象的名字
以上最后一行代码存在错误,因为它会把两个Person对象的姓名都改为“王小虹”。由此可见,使用可变类更容易使程序代码出错。因为随意改变一个可变类对象的状态,有可能会导致与之关联的其他对象的状态被错误地改变。
不可变类的实例在实例的整个生命周期中永远保持初始化的状态,它没有任何状态变化,简化了与其他对象之间的关系。不可变类具有以下优点:
l 不可变类能使程序更加安全,不容易出错。
l 不可变类是线程安全的,当多个线程访问不可变类的同一个实例时,无须进行线程的同步。
由此可见,应该优先考虑把类设计为不可变类,假使必须使用可变类,也应该把可变类尽可能多的属性设计为不可变的,即用final修饰符来修饰,并且不对外公开用于改变这些属性的方法。
在创建不可变类时,假如它的属性的类型是可变类型,在必要的情况下,必须提供保护性拷贝,否则,这个不可变类实例的属性仍然有可能被错误地修改。这条建议同样适用于可变类中用final修饰的属性。
例如例程11-10的Schedule类包含学校的开学时间和放假时间信息,它是不可变类,它的两个属性start和end都是final类型,表示不允许被改变,但是这两个属性都是Date类型,而Date类是可变类。
例程11-10 Schedule.java
import java.util.Date;
public final class Schedule{
private final Date start; //开学时间,不允许被改变
private final Date end; //放假时间,不允许被改变
public Schedule(Date start,Date end){
//不允许放假日期在开学日期的前面
if(start.compareTo(end)>0)
throw new IllegalArgumentException(start +" after " +end);
this.start=start;
this.end=end;
}
public Date getStart(){return start;}
public Date getEnd(){return end;}
}
尽管以上Schedule类的start和end属性是final类型的,但由于它们引用Date对象,在程序中可以修改所引用Date对象的属性。以下程序代码创建了一个Schedule对象,接下来把开学时间和放假时间都改为当前系统时间。
Calendar c= Calendar.getInstance();
c.set(2006,9,1);
Date start=c.getTime();
c.set(2007,1,25);
Date end=c.getTime();
Schedule s=new Schedule(start,end);
end.setTime(System.currentTimeMillis()); //修改放假时间
start=s.getStart();
start.setTime(System.currentTimeMillis()); //修改开学时间
为了保证Schedule对象的start属性和end属性值不会被修改,必须为这两个属性使用保护性拷贝,参见例程11-11。
例程11-11 采用了保护性拷贝的Schedule.java
import java.util.Date;
public final class Schedule {
private final Date start;
private final Date end;
public Schedule(Date start,Date end){
//不允许放假日期在开学日期的前面
if(start.compareTo(end)>0)throw new IllegalArgumentException(start +" after " +end);
this.start=new Date(start.getTime()); // 采用保护性拷贝
this.end=new Date(end.getTime()); // 采用保护性拷贝
}
public Date getStart(){return (Date)start.clone() ;} // 采用保护性拷贝
public Date getEnd(){return (Date)end.clone() ;} // 采用保护性拷贝
}
通过采用保护性拷贝,其他程序无法获得与Schedule对象关联的两个Date对象的引用,因此也就无法修改这两个Date对象的属性值。
发表评论
-
ofbiz 之entity实体
2014-03-25 18:16 955ofbiz 之entity实体 1. 实体定义文件 实体定 ... -
ofbiz迷你语言
2012-08-08 17:13 2310simple-map-processor 和 sim ... -
ofbiz之entity 实体解析
2012-08-08 17:12 1525ofbiz 之entity实体 1. 实体定义文件 实体定 ... -
ofbiz之旅-实体简介(中英译)
2012-08-09 09:34 1183OFBIZ ENTITY ENGINE COOKBOOK = ... -
OFBIz之旅[结构]
2012-08-08 17:03 1505OFBIz之旅[结构] 注意: 1,持久层,在OFBI ... -
java concurrent 探秘(2)
2011-08-08 14:21 927java concurrent 探秘(2) Blo ... -
java concurrent 探秘
2011-08-08 11:02 828java concurrent 探秘 我们都知道,在JD ... -
one-to-one 一对一主键关联映射_单向
2011-08-03 17:22 1337one-to-one 一对一主键关联映射_单向 一对一主键关 ... -
JavaScript验证正则表达式大全
2011-07-27 17:18 934上篇文章《JavaScript验证正则表达式大全》说的是jav ... -
JavaScript验证正则表达式大全
2011-07-27 17:17 842JavaScript验证正则表达式大全 JavaScript验 ... -
js 收集1
2011-01-14 09:49 10741.javascript的数组API Js代码 ... -
struts 核心解析
2010-12-03 14:25 2468一、概述 Struts2的核心是一个Fil ... -
Java类库中的集合类解析
2010-11-29 16:05 1098这篇我准备从源码的高度来看看集合中各个实现类的是如何组织我们存 ... -
jboss classloader机制以及scope配置
2010-11-29 15:06 17261. 概念介绍 UCL : org.jboss.mx. ... -
总结和对比一下(jboss,tomcat,jetty)容器的classloader机制
2010-11-29 14:58 1999总结和对比一下(jboss,tomcat,je ... -
jboss,tomcat,jetty 容器的classloader机制
2010-11-29 14:53 4602背景 前段时间一直在做应用容器的迁移,将公司的应用 ... -
Session,Cookie,jsessionid和Url重写
2010-11-29 12:55 1940Session,Cookie,jsessionid ... -
DWR work
2010-11-25 18:14 902这段时间较闲,研究了一 ... -
CXF jaxws spring configuration
2010-11-19 16:27 1608最近在cxf-zh中有人问及了有关Spring配置CXF Cl ... -
线程安全总结2
2010-11-17 16:48 830站内很多人都问我,所谓线程的“工作内存”到底是个什么东西? ...
相关推荐
在函数参数传递方面,可变类型和不可变类型有着本质的区别。当一个不可变类型的数据作为参数传递给函数时,函数内部的任何修改都不会影响到原始数据,因为新的数据会存储在一个新的内存地址中。但在可变类型的数据被...
在Python编程语言中,对象分为可变对象和不可变对象,这一特性对于理解和优化代码...掌握可变对象和不可变对象的区别,以及如何正确地使用`is`和`==`,可以帮助我们更好地理解和调试程序,避免潜在的错误和性能问题。
Java String类为什么是不可变的_动力节点Java学院整理,动力节点口口相传的Java黄埔军校
固体介质可变电容器是在其动片与定片(动、定片均为不规则的半圆形金属片)之间加下云母片或塑料(聚苯乙烯等材料)薄膜作为介质,外壳为透明塑料。其优点是体积小、重量轻;缺点是杂声大、易磨
Java中的不可变类机制是一种设计模式,用于创建对象在创建后其状态无法改变的类。不可变类在多线程环境中特别有用,因为它们天生线程安全,无需额外的同步措施。不可变类的一些典型例子包括`Integer`、`Long`和`...
在Python编程语言中,列表和元组是两种非常重要的数据结构,它们在存储和操作数据时...理解这两者之间的区别并熟练运用,是Python编程基础中不可或缺的一部分。通过学习和实践,我们可以更好地优化代码,提高程序性能。
在JavaScript中,虽然原始类型(如字符串、数字和布尔值)本身就是不可变的,但复杂的数据结构如数组和对象则是可变的。 ### 不可变操作的重要性 1. **防止意外修改**:不可变操作确保数据在任何时候都不会被意外...
在 Java 中实现不可变类是提高程序安全性和可维护性的重要手段,尤其是在函数式编程中。不可变类的核心特性是其对象一旦创建,其状态就不能再发生改变。这是因为不可变对象具有以下优点: 1. **线程安全**:由于...
不可变对象由于其不可变性,更易于进行引用计数,而可变对象可能涉及更复杂的引用关系,如循环引用,需要更复杂的垃圾回收策略。 总的来说,了解Python中的可变与不可变数据类型及其特性,可以帮助我们更好地控制...
3. **效率与适应性**:由于可变字节码是动态调整字节数的,因此它特别适合那些数值分布不均匀的数据集。如果数据集中存在大量重复的小数值,可变字节码的压缩效果会更好。同时,它也能很好地适应数据量的变化,无论...
注意:这里的可变不可变指的是内存中的那块内容(value)是否可以被改变。如果是不可变类型的话,在对对象本身操作的时候,必须在内存中新申请一块区域(因为老区域不可变)。如果是可变类型,在对对象操作的时候,...
可变参数与数组的区别 虽然可变参数在语法上类似于数组,但它们在实际使用中有以下几点不同: - **可变参数不是数组变量**:可变参数只是一个语法上的便利,它在内部会被转换为数组,但你不能直接获取到它的长度...
Java中的不可变类(immutable)是一种特殊的类,其对象一旦创建后,其状态就不能再发生变化。这类类在Java中有着重要的地位,特别是String类,它是Java中最常用的不可变类之一。不可变类的设计旨在提高安全性、效率...
值得注意的是,在C51环境下,可变参数函数的处理方式与标准C环境中的处理方式在本质上是相同的,但是可能会有一些特定于平台的限制或者细微差异。例如,某些特定的硬件平台可能对内存访问或者数据对齐有特殊要求,...
1. final变量的细节特征: 1. Java核心类库就提供了很多不可变类: 因此可以放心使用 2. 如何设计自定义的不可变类呢 3. 可变类型数据成
来看个不可变类示例:ThreeStooges类是一个不可变类, 它的状态在创建后不能再修改,所有域都是final类型,并且它被正确创建(创建期间没有发生this引用的逸出)。该类有三个方法:isStooge、getStoogeNames,都是...
此外,由于字符串的不可变性,从而可以让其 hashCode 也被缓存,在 Java 里面哈希类数据结构如 HashMap, HashTable,HashSet 其 key 用的最多的基本都是 String 类型,如此一来 key 的 hashCode 的也可以在第一次调用...
不可变类:当你获得这个类的一个实例引用时,你不可以改变这个实例的内容。 那么,什么是不可变对象? 一旦一个类的实例化对象被创建并初始化,那么它不可以被改变。我们可以调用访问器方法(getter),...
【可变电阻器外形特征】关于可变电阻器外形特征说明下列几点:可变电阻器的外形与普通电阻器在外形上有很大的区别,它具有下列一些特征,根据这些特征可以在线路板中识别可变电阻器:(1)可变电阻器的体积比一般...
3. 可变参数与数组的区别: 尽管可变参数在语法上看起来像是多个参数,但实际上它们是单个数组参数。这意味着,你可以在同一个函数中混合使用固定参数和可变参数,但可变参数必须是参数列表的最后一个。 4. 可变...