【发布时间】:2012-07-10 11:34:41
【问题描述】:
我使用 TreeMap 作为另一个 TreeMap 中的“键”
即
TreeMap<TreeMap<String, String>, Object>
在我的代码中,“对象”是一个个人构造,但在这个例子中,我使用了一个字符串。
我创建了一对 TreeMap 来测试 TreeMap.CompareTo() 和 TreeMap.HashCode() 方法。这从以下开始...
public class TreeMapTest
public void testTreeMap()
{
TreeMap<String, String> first = new TreeMap<String, String>();
TreeMap<String, String> second = new TreeMap<String, String>();
first.put("one", "une");
first.put("two", "deux");
first.put("three", "trois");
second.put("une", "one");
second.put("deux", "two");
second.put("trois", "three");
TreeMap<TreeMap<String, String>, String> english = new TreeMap<TreeMap<String, String>, String>();
TreeMap<TreeMap<String, String>, String> french = new TreeMap<TreeMap<String, String>, String>();
english.put(first, "english");
french.put(second, "french");
我现在从这里调用英文项目,看看它是否包含密钥
if (english.containsKey(second))
{
System.out.println("english contains the key");
//throws error of ClassCastException: Java.util.TreeMap cannot be cast to
//Java.Lang.Comparable, reading the docs suggests this is the feature if the key is
//not of a supported type.
//this error does not occur if I use a HashMap structure for all maps, why is
//this key type supported for one map structure but not another?
}
但是我应该注意 HashMap 和 TreeMap 都指向 AbstractMap 父级中的同一个 HashCode() 方法。
我的第一个想法是将我的 TreeMap 转换为 HashMap,但这似乎有点笨拙!所以我决定将 hashCode() 方法应用于 2 个树形图对象。
int hc1 = first.hashCode();
int hc2 = second.hashCode();
if(hc1 == hc2)
{
systom.out.printline("values are equal " + hc1 + " " + hc2);
}
打印以下内容
values are equal 3877431 & 3877431
对我来说hashcode应该不同,因为key值不同,我找不到HashMap和TreeMap之间hashCode()方法的实现差异的细节。
请不要以下。 仅将 Keys 更改为 HashMap 不会停止 ClassCastException 错误。将所有映射更改为 HashMap 即可。所以 TreeMap 中的 containsKey() 方法有些东西不能正常工作,或者我误解了 - 谁能解释一下?
获取第一个和第二个映射对象的 hashCode 的部分总是产生相同的输出(无论我在这里使用哈希映射还是树映射)但是 if(english.ContainsKey(second)) 不会打印使用 HashMap 时的任何消息,因此 HashMap 实现中的某些内容显然与 compareTo() 方法不同。
我的主要问题是。
在哪里可以找到用于 TreeMap 对象的键类型的详细信息(以防止将来出现“ClassCastException”错误)。
如果我不能使用某种类型的对象作为键,为什么我首先允许将它作为键插入到 TreeMap 中? (当然,如果我可以插入它,我应该能够检查密钥是否存在?)
任何人都可以提出另一个命令 inster/retrieves 来替换我的 TreeMap 键对象的构造吗?
或者我是否可能发现了奇怪的行为。根据我的理解,我应该能够将 TreeMap 替换为 HashMap,还是我偶然发现了一个边缘场景?
提前感谢您的 cmets。
大卫。
ps。这个问题在我的代码中不是问题,因为我使用个人实用程序来创建一个依赖于键和值对的哈希(即我计算键哈希值与值哈希值不同......对不起,如果是一个令人困惑的句子!)我假设 hashCode 方法只是将所有值加在一起,而不考虑项目是键还是值。
pps。我不确定这是否是一个好问题,有没有关于如何改进它的建议?
编辑。
人们似乎认为我在做一些花哨的语言词典,这对我的例子并不感到意外,对此深表歉意。我用这个作为例子,因为它很容易进入我的脑海,写得很快,并展示了我的问题。
真正的问题如下。
我正在访问一个遗留数据库结构,它不能很好地与任何东西对话(结果集不是正向和反向可读等)。所以我抓取数据并从中创建对象。 最小的对象代表表中的一行(这是在上面的示例中我使用字符串值 'english' 或 'french' 的对象。
我有这些rowObjects的集合,每一行都有一个明显的key(这是指向相关rowObject的TreeMap)。
我不知道这是否能让事情变得更清楚!
编辑 2。
我觉得我需要进一步详细说明我使用的原始选择
hashMap<HashMap<String,string>, dataObject>
对于我的数据结构,然后转换为 TreeMap 以获得有序视图。
在编辑 1 中,我说旧版 DB 不能很好地运行(我怀疑这是 JDBC.ODBC 的问题,我不打算购买 JDBC 来与 DB 通信)。事实上,我在创建 java 'dataObject' 时对数据进行了一些修改。这意味着虽然 DB 可能会以升序或降序的方式吐出结果,但我无法知道它们以什么顺序插入到我的 dataObject 中。使用 likeHashMap 似乎是一个不错的解决方案(请参阅 duffymo 的建议),但我稍后需要以有序的方式提取数据,而不仅仅是连续提取数据(LinkedHashMap 仅保留插入顺序),而且我不倾向于乱排序所有内容和当我需要在另外两个项目之间插入一个新项目时制作副本,TreMap 会为我执行此操作......但如果我为键创建一个特定对象,它将只包含一个 TreeMap 作为成员,显然我将需要提供 compareTo 和 hashCode 方法。那么为什么不只是扩展 TreeMap(尽管 Duffymo 有一点要放弃该解决方案)!
【问题讨论】:
-
您应该阅读 TreeMap 文档。 TreeMap 不是 HashMap。它不使用
hashCode()。它的键应该是可比较的,因为 TreeMap 的重点是在内部使用可比较对象的树。 docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html -
TreeMap键必须是它们自己的Comparable,或者您必须提供一个可以比较它们的键的Comparator。 -
@JBNizet 我已阅读文档docs.oracle.com/javase/7/docs/api/index.html?java/util/…(注意我使用的是 java 7 而不是 6)。它声明hashcode是从abstractMap继承的,就像HashMap的hashcode
-
TreeMap 不会在其 键 上调用 hashCode()。 TreeMap 的 hashCode() 方法被继承的事实与我的评论无关。您的帖子一直在谈论 hashCode(),但 hashCode() 与 TreeMap 完全无关。 TreeMap 不关心其键的 hashCode。
-
@JBNizet 文档指出 TreMap.put(k,v) 抛出:ClassCastException - 如果指定的键无法与地图中当前的键进行比较。因此,如果 TreeMap 在其继承的某处未同时实现可比较代码和哈希码,我将无法在不引发错误的情况下将其用作键(这不会发生)。这可能是对我的问题的更好描述。 TreeMap 显然没有可比性,所以我不应该在我的 TreeMap 中使用一个作为键。
标签: java dictionary hashcode treemap compareto