`
sunxboy
  • 浏览: 2828705 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

java可变量与不可变量实践

阅读更多

StringHolder是一个可变类(Mutable Class),不适合作为key

 

 

import java.util.HashSet;

public class StringHolder {
	private String string;

    public StringHolder(String s) {
        this.string = s;
    }

    public String getString() {
        return string;
    }

    public void setString(String string) {
        this.string = string;
    }

    public boolean equals(Object o) {
        if (this == o)
            return true;
        else if (o == null || !(o instanceof StringHolder))
            return false;
        else {
            final StringHolder other = (StringHolder) o;
            if (string == null)
                return (other.string == null);
            else
                return string.equals(other.string);
        }
    }

    public int hashCode() {
        return (string != null ? string.hashCode() : 0);
    }

    public String toString() {
        return string;
    }
    
    public static void main(String[] args) {
    	StringHolder sh = new StringHolder("blert");
        HashSet h = new HashSet();
        h.add(sh);
        sh.setString("moo");
        System.out.println(h.contains(sh));
        System.out.println(h.size());
        System.out.println(h.iterator().next());
	}

 

 

 编写不变类很容易。如果以下几点都为真,那么类就是不变的:

1. 所有的成员变量是 final 

2. 类声明为 final

3.  在构造方法中,this的引用不会被修改

4.  如其包含的可变量的成员变量,如 array, collection。满足:

   a. 是private的

   b. 无返回值,或不会被外部调用

   c. 是被引用对象的唯一引用

   d. 在构造方法调用后,不会被修改状态 


最后一组要求似乎挺复杂的,但其基本上意味着如果要存储对数组或其它可变对象的引用,就必须确保您的类对该可变对象拥有独占访问权(因为不然的话,其它类能够更改其状态),而且在构造后您不修改其状态。为允许不变对象存储对数组的引用,这种复杂性是必要的,因为 Java 语言没有办法强制不对 final 数组的元素进行修改。注:如果从传递给构造函数的参数中初始化数组引用或其它可变字段,您必须用防范措施将调用程序提供的参数或您无法确保具有独占访问权的其它信息复制到数组。否则,调用程序会在调用构造函数之后,修改数组的状态。清单 3 显示了编写一个存储调用程序提供的数组的不变对象的构造函数的正确方法(和错误方法)。

如:

 

public class ImmutableArrayHolder {
	private final int[] theArray;

	// Right way to write a constructor -- copy the array
	public ImmutableArrayHolder(int[] anArray) {
		this.theArray = (int[]) anArray.clone();
	}

	// Right way to write an accessor -- don't expose the array reference
	public int getArrayLength() {
		return theArray.length;
	}

	public int getArray(int n) {
		return theArray[n];
	}

	// Right way to write an accessor -- use clone()
	public int[] getArray() {
		return (int[]) theArray.clone();
	}
 

 

偶尔更改的数据

有些数据项在程序生命期中一直保持常量,而有些会频繁更改。常量数据显然符合不变性,而状态复杂且频繁更改的对象通常不适合用不变类来实现。那么有时会更改,但更改又不太频繁的数据呢?有什么方法能让 有时更改的数据获得不变性的便利和线程安全的长处呢?

util.concurrent 包中的 CopyOnWriteArrayList 类是如何既利用不变性的能力,又仍允许偶尔修改的一个良好示例。它最适合于支持事件监听程序的类(如用户界面组件)使用。虽然事件监听程序的列表可以更改,但通常它更改的频繁性要比事件的生成少得多。

除了在修改列表时, CopyOnWriteArrayList 并不变更基本数组,而是创建新数组且废弃旧数组之外,它的行为与ArrayList 类非常相似。这意味着当调用程序获得迭代器(迭代器在内部保存对基本数组的引用)时,迭代器引用的数组实际上是不变的,从而可以无需同步或冒并发修改的风险进行遍历。这消除了在遍历前克隆列表或在遍历期间对列表进行同步的需要,这两个操作都很麻烦、易于出错,而且完全使性能恶化。如果遍历比插入或除去更加频繁(这在某些情况下是常有的事), CopyOnWriteArrayList 会提供更佳的性能和更方便的访问。

 

分享到:
评论

相关推荐

    Java变量类型常见面试题及答案

    在Java中,变量是存储数据的基本单元,对于面试来说,理解和掌握Java变量类型是必不可少的。本文提供了二十道常见的面试题,涵盖了Java中的基本数据类型、引用数据类型、作用域、初始化等方面的知识点。这些问题旨在...

    java环境变量设置.bat

    java环境变量设置 bat 运行,bat 可放任意目录!!! 在运行本bat文件前,记得先修改你java\jdk的路径。 在网络上找了很久没有一个很好用的,而且很多都不成功,还是自己写个比较实在,而且不影响本来path的设置!!...

    JAVA类的方法调用和变量

    JAVA类的方法调用和变量 一、类的分类: 1、普通类 2、抽象类(含有抽象方法的类) 3、静态类(不需要实例化,就可以使用的类) 二、方法的分类: 1、私有方法(只有类的内部才可以访问的方法) 2、保护方法(只有...

    word读取并替换内容(table与变量都可替换)

    读取word稳定并进行内容替换,table与其余变量都可进行替换,程序可以直接导入运行,jar都带着

    Java项目开发与毕业设计指导

    安装JDK,并正确配置环境变量(如果有疑问,可以参考任何一本java入门书籍)。打开Eclipse(可以到http://www.eclipse.org/现在官方最新版,Eclipse本身是免费软件),导入ch01下的java项目,然后保存、运行game....

    Java并发编程实践 PDF 高清版

    3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 第5章 构建块 5.1 同步容器 5.2 发容器 5.3 阻塞队列和...

    生成java可执行文件

    本文主要告诉大家如何实现两个功能:①让java程序(class文件)像exe文件一样方便运行;...无意中发现了一个法子,简单而又实用,甚至不需要你去在计算机上设置环境变量等种种繁琐操作。特以此分享。

    JAVA并发编程实践_中文版(1-16章全)_1/4

    3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 第5章 构建块 5.1 同步容器 5.2 发容器 5.3 阻塞队列和...

    Java理论与实践:流行的原子

    本文介绍了要使用多处理器系统的功能,通常需要使用多线程构造应用程序。...然后,java.util.concurrent中的类基于这些低级原子变量工具构建,为它们提供比以前执行相似功能的类更显著的可伸缩性优点。

    dotenv-java:DoDotenv是一个无深度的纯Java模块,可从.env文件加载环境变量

    但是,在运行多个项目的开发机器或连续集成服务器上设置环境变量并不总是可行的。 启动环境后,Dotenv将.env文件中的变量加载到ENV中。 -主机环境中列出的环境变量将覆盖.env中的环境变量。 使用dotenv.get("...")...

    Java Stream 使用详解

     Stream和其它集合类的区别在于:其它集合类主要关注与有限数量的数据的访问和有效管理(增删改),而Stream并没有提供访问和管理元素的方式,而是通过声明数据源的方式,利用可计算的操作在数据源上执行,当然...

    JAVA_API1.6文档(中文)

    javax.sql.rowset.serial 提供实用工具类,允许 SQL 类型与 Java 编程语言数据类型之间的可序列化映射关系。 javax.sql.rowset.spi 第三方供应商在其同步提供者的实现中必须使用的标准类和接口。 javax.swing 提供...

    深入Java虚拟机(原书第2版).pdf【附光盘内容】

    《深入Java虚拟机(原书第2版)》,原书名《Inside the Java Virtual Machine,Second Edition》,作者:【美】Bill Venners,翻译:曹晓钢、蒋靖,出版社:机械工业出版社,ISBN:7111128052,出版日期:2003 年 9 ...

    华为java培训讲义

    1、文件名必须和public修饰的类名一致,以.java作为文件后缀,如果定义的类不是public的,则文件名与类名可以不同。 2、一个.java文件中可以有多个class,但是只有一个public修饰的类。 3、java源代码文件编译...

    Java并发编程实战

    第1章 简介 1.1 并发简史 1.2 线程的优势 1.2.1 发挥多处理器的强大能力 1.2.2 建模的简单性 1.2.3 异步事件的简化处理 ...第15章 原子变量与非阻塞同步机制 第16章 Java内存模型 附录A 并发性标注 参考文献

    Java并发编程实践part1

    3.4 不可变性 3.5 安全发布 . 第4章 组合对象 4.1 设计线程安全的类 4.2 实例限制 4.3 委托线程安全 4.4 向已有的线程安全类添加功能 4.5 同步策略的文档化 第5章 构建块 5.1 同步容器 5.2 发容器 5.3 阻塞队列和...

    java基础总结大全

    (1)path是配置Windows可执行文件的搜索路径,即扩展名为.exe的程序文件所在的目录, 用于指定DOS窗口命令的路径。 (2)Classpath是配置class文件所在的目录,用于指定类搜索路径,JVM就是通过它来寻找该类的class...

    典型JAVA面试试题及答案.pdf

    修饰变量的时候表示这个变量不可被更改并且必须赋初始值; 修饰方法的时候表示方式不可被重写。finally 通常和try-catch 一起, 在finally 里代码无论是否发生异常都会执行到finalize 是一个方法名。方式是定义在...

    Java中this与super的区别

    在Java中,有时还会遇到子类中的成员变量或方法与超类(有时也称父类) 中的成员变量或方法同名。因为子类中的成员变量或方法名优先级高, 所以子类中的同名成员变量或方法就隐藏了超类的成员变量或方法, 但是...

    【Java语言基础】final关键字

    final修饰变量时,表示该变量一旦获得了初始值之后就不可被改变,final既可修饰成员变量(包括类变量和实例变量),也可以修饰局部变量,形参。 final修饰成员变量 类变量:当类初始化时,系统会为类变量分配内存,...

Global site tag (gtag.js) - Google Analytics