在Java中将Hashtable创建为final的方法

61

正如我们所知,"final"关键字在Java中的作用是什么。在声明变量时使用"final",我们必须初始化该变量,例如"final int a = 10;"。 我们无法更改"a"的值。但如果我们使用HashTable,即使将其声明为final,也可以添加一些值。

示例:

 private static final Hashtable<String,Integer> MYHASH = new Hashtable<String,Integer>() 
{{     put("foo",      1);     
       put("bar",      256);     
       put("data",     3);     
       put("moredata", 27);     
       put("hello",    32);     
       put("world",    65536);  }}; 

现在我将MYHASH哈希表声明为final。但如果我尝试添加更多元素,它会被接受。

MYHASH.put("NEW DATA",      256);

现在,“NEW DATA”已添加到哈希表中。 我的问题是,为什么即使声明为final,它也允许添加?


请注意,如果映射的内容是可变的(例如java.util.Datejava.awt.Point),则它仍然是可变的。 - Tom Hawtin - tackline
6个回答

121

因为 final 标记的是引用,而不是对象本身。你无法将该引用指向不同的哈希表。但你可以对该对象进行任何操作,包括添加和删除内容。

你举的 int 的例子是基本类型,而不是引用类型。Final 意味着你无法更改变量的值。因此,对于一个 int,你无法改变变量的值,比如让这个 int 的值不同。对于对象引用,你无法改变引用的值,也就是它所指向的对象。


24
你可以使用Collections.unmodifiableMap来获取一个不可修改的哈希表包装器。

示例:

import java.util.*;
class Test{

    public static final Map<String,Integer> MYHASH;
    static{
        Hashtable<String,Integer> tmp = 
            new Hashtable<String,Integer>();
        tmp.put("A",65);
        tmp.put("C",67);
        MYHASH = Collections.unmodifiableMap(tmp);
    }

    public static void main(String[] args){

        System.out.println(MYHASH.get("A"));

        //this will throw
        //java.lang.UnsupportedOperationException
        MYHASH.put("B",66);    

    }

}

1
你得到我的+1,因为你显然没有保留即将被无意中改变的可变地图版本。我更喜欢保留不可变的静态“private”。而且使用“Hashtable”也没有意义。 - Tom Hawtin - tackline
谢谢!为了与问题保持一致,我选择了Hashtable,但我没有注意到private - Vlad

16

只有引用是final的,它的方法当然可以像非final引用一样被调用。

使用Collections.unmodifiableMap(map)使得map不可修改。


8
尝试使用Collections.unmodifiableMap( MYHASH )将您的Hashtable封装为不可修改的映射。当您尝试更改映射中的内容时,例如添加或删除条目,它应该会引发异常。(请注意,MYHASH 现在应该是 Map<String, String> 类型,而不是 Hashtable<String, String> 类型。)
关于final关键字:正如其他人已经说过的那样,这意味着您不能将另一个Hashtable赋值给MYHASH,但是映射本身仍然是可变的。要更改这一点,您必须将其封装到某个不可变的包装器中,例如上面提到的UnmodifiableMap

6

正如乔所说,这是因为final标记的是引用而不是对象本身。

然而,您可以使用Collections.unmodifiableMap(在此处查看来实现您想要的操作。


3

对于字段和变量,使用final意味着它们只能被赋值一次。可以立即赋值,或在以后的某个时间(例如,在字段的构造函数中)。这并不意味着实际实例变得不可变。Hashtable是一种数据结构,可以添加条目,而不管它被分配给某个变量的方式如何。只有引用是final。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接