`
sunxboy
  • 浏览: 2869265 次
  • 性别: 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环境变量配置 JDK环境变量

    执行一个可执行文件时,如果该文件不能在当前路径下找到,则依次寻找`PATH`中的每一个路径,直至找到。Java的编译命令(`javac`)、执行命令(`java`)和一些工具命令(`javadoc`, `jdb`等)都在其安装路径下的`bin`目录中...

    java环境变量配置

    如果没有正确设置这个变量,编译Java源代码时可能会遇到找不到类的问题。 ##### 4.2 配置步骤 1. **打开系统属性**:同上。 2. **新建CLASSPATH变量**: - 在“系统变量”区域点击“新建”按钮。 - 输入变量名:`...

    java环境变量设置

    在进行Java环境变量设置时,应确保遵循以下最佳实践: - 避免直接在PATH中包含JRE的路径,因为JRE的版本可能与JDK不同,这可能导致冲突。 - 使用相对路径而不是绝对路径,以提高移植性。 - 如果有多个Java版本,...

    java环境变量的设置

    - **Path**:该变量用于告诉操作系统Java的可执行文件(如javac.exe和java.exe)所在的位置。 - **Classpath**:该变量用于指定Java虚拟机(JVM)加载类(class)文件的路径。 #### 三、设置Java环境变量 接下来,...

    JAVA环境变量设置

    本文将详细介绍如何在Windows操作系统中进行JAVA环境变量的设置,主要包括`JAVA_HOME`、`CLASSPATH`以及`PATH`三个关键环境变量的配置步骤与作用。 #### 二、JAVA_HOME环境变量 **定义**:`JAVA_HOME`环境变量是...

    java 常量与变量

    常量提供不可变的数据,而变量则允许数据在程序运行过程中变化。合理地声明、初始化和使用常量与变量,能帮助我们编写出清晰、可维护的代码。在实际编程中,还需根据需求选择合适的数据类型,并注意变量的作用域和...

    Java 成员变量和局部变量

    3. **无法被访问控制修饰符修饰**: 局部变量不能有public、private、protected或包访问权限,因为它们的作用域仅限于当前代码块。 4. **没有默认初始化**: 局部变量不会自动初始化,必须明确赋值后才能使用。 理解...

    Java环境变量设置

    ### Java环境变量设置详解 #### 一、Java环境变量的重要性 在计算机系统中,环境变量是一种重要的配置方式,用于指示操作系统或程序如何运行。对于Java开发者来说,正确配置Java环境变量是确保Java程序能够顺利...

    配置java环境变量

    如果`Classpath`变量不存在,可以创建一个;如果存在,则在原有值后添加`;`符号,然后加入`%JAVA_HOME%\lib`。这允许Java虚拟机(JVM)访问到类库和其他资源。 #### 步骤四:修改Path环境变量 最后,更新`Path`...

    批处理设置java环境变量

    当我们在命令行输入`java`或`javac`等命令时,系统会在PATH变量包含的目录下寻找对应的可执行文件。 3. **CLASSPATH**:这个变量告诉Java虚拟机(JVM)在哪里可以找到类库,即.class文件。如果未设置或设置不正确,...

    设置Java环境变量

    Java环境变量是Java开发和运行过程中必不可少的配置项,它们指示操作系统如何找到Java开发工具(如JDK)和运行Java应用程序。这篇文档将详细介绍如何使用VBScript(Visual Basic Script)来自动化设置Java环境变量的...

    Java环境变量一键设置.zip

    Java开发过程中,环境变量的配置是必不可少的步骤,特别是对于初学者来说,这往往是一项繁琐的任务。本资源“Java环境变量一键设置.zip”提供了一种便捷的方法,旨在帮助用户快速在Windows 7及更高版本的操作系统上...

    java环境变量一键配置

    Java环境变量配置是Java开发中不可或缺的一环,它使得操作系统能够找到Java开发工具集(JDK)的位置,进而运行Java程序。本教程将详细介绍如何通过一键配置的方式设置Java环境变量,以便于开发者更加高效地进行Java...

    Java环境变量一键配置.exe,很实用

    Java开发和运行过程中,环境变量的配置是必不可少的步骤,特别是对于初学者来说,这个过程可能会显得有些繁琐。"Java环境变量一键配置.exe" 文件就是为了简化这个过程而设计的工具,它能帮助用户快速、方便地设置好...

    java环境变量自动配置for windows

    这些环境变量指导系统找到Java可执行文件、Java开发工具以及类库。 1. **JAVA_HOME**:这个变量指向JDK的安装目录,例如`C:\Program Files\Java\jdk1.8.0_202`。设置这个变量有助于其他依赖Java的软件或工具定位JDK...

    Java环境变量一键配置

    Java环境变量一键配置工具是为了简化Java开发环境的搭建过程,特别是对于那些不熟悉操作系统环境变量配置的用户来说,这是一个非常方便的解决方案。在传统的Java开发环境中,安装Java Development Kit (JDK) 后,...

    配置java环境变量一键生成

    Java环境变量配置是Java开发中不可或缺的一环,它允许操作系统找到Java开发工具(JDK)的位置,以便正确执行Java程序。本教程将详细介绍如何通过"Java环境变量一键配置"工具来简化这一过程。 首先,我们需要了解...

    EnviromentSet(Java环境变量)源码.zip

    - `PATH`: 需要将`%JAVA_HOME%\bin`(Windows)或`$JAVA_HOME/bin`(Unix/Linux)添加到系统路径中,这样命令行可以找到Java可执行文件,如`java`, `javac`, 和 `jar`等。 - `CLASSPATH`: 定义了类加载器寻找类...

Global site tag (gtag.js) - Google Analytics