我在另一个TreeMap中使用TreeMap作为'key'
即
TreeMap<TreeMap<String, String>, Object>
在我的代码中,'object'是一个个人构造,但对于这种情况,我使用了一个字符串。
我创建了一对TreeMaps来测试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个treemap对象。
int hc1 = first.hashCode();
int hc2 = second.hashCode();
if(hc1 == hc2)
{
systom.out.printline("values are equal " + hc1 + " " + hc2);
}
打印以下内容
values are equal 3877431 & 3877431
对我来说,哈希码应该是不同的,因为键值不同,我找不到HashMap和TreeMap之间hashCode()方法的实现差异的细节。
请不要以下。 仅将Keys更改为HashMap不会停止ClassCastException错误。将所有映射更改为HashMap可以。所以TreeMap中的containsKey()方法有些不能正常工作,或者我误解了 - 有人可以解释一下吗?
我得到第一个和第二个地图对象的hashCode的部分总是产生相同的输出(无论我在这里使用哈希或树图)但是if(english.ContainsKey(second))不打印使用HashMaps时的任何消息,因此HashMap实现中显然有一些与compareTo()方法不同的消息。
我的主要问题是。
在哪里可以找到在TreeMap对象中使用的键类型的详细信息(以防止将来出现'ClassCastException'错误)。
如果我不能使用某种类型的对象作为键,为什么我首先允许将它作为键插入到TreeMap中? (当然,如果我可以插入它,我应该能够检查密钥是否存在?)
任何人都可以建议另一个命令inster / retrieval来替换我的TreeMap密钥对象的构造吗?
或者我有可能发现奇怪的行为。根据我的理解,我应该能够为HashMap替换TreeMap,或者我偶然发现了一个边缘场景?
提前感谢您的意见。
大卫。
PS。问题不是我的代码中的问题,因为我使用个人实用程序来创建一个依赖于键和值对的哈希(即我计算键哈希值与值哈希值不同...对不起,如果是一个令人困惑的句子!)我假设hashCode方法只是将所有值加在一起而不考虑项是键还是值。
PPS。我不确定这是不是一个好问题,关于如何改进它的任何指示?
编辑。
从回复中人们似乎认为我正在做一些奇特的语言词典,不是我的例子中的一个惊喜,所以很抱歉。我用它作为一个例子,因为它很容易出现在我的大脑中,很快就能写出来并证明了我的问题。
真正的问题如下。
我正在访问一个遗留的数据库结构,它并没有很好地与任何东西交谈(结果集不是正向和反向可读等)。所以我抓住数据并从中创建对象。 最小的对象表示表中的一行(这是上面示例中我使用字符串值'english'或'french'的对象。
我有这些rowObject的集合,每一行都有一个明显的键(这是指向相关rowObject的TreeMap)。
我不知道这是否让事情变得更清楚了!
编辑2。
我觉得我需要进一步详细说明我选择的原始使用
hashMap<HashMap<String,string>, dataObject>
表示我的数据结构,然后转换为TreeMap以获得有序视图。
在编辑1中,我说遗留数据库不能很好地发挥作用(这是我怀疑的JDBC.ODBC的一个问题,而且我不打算获取JDBC来与数据库通信)。事实是我对数据应用了一些修改,就像我创建java'dataObject'一样。这意味着尽管DB可能会按升序或降序吐出结果,但我无法知道它们插入到dataObject中的顺序。使用likesHashMap似乎是一个很好的解决方案(请参阅duffymo的建议),但后来我需要以有序的方式提取数据,而不仅仅是连续提取(LinkedHashMap只保留插入顺序),而且我不会痴迷于订购所有内容和当我需要在2个其他人之间插入一个新项目时,TreMap会为我做这个...但是如果我为这个键创建一个特定的对象,它将只包含一个TreeMap作为成员,显然我将需要提供compareTo和hashCode方法。那么为什么不仅仅是范围TreeMap(尽管Duffymo有一个关于抛出该解决方案的观点)!
答案 0 :(得分:6)
这不是个好主意。映射键必须是不可变的才能正常工作,而你的不是。
你真的想做什么?当我看到人们用数据结构做这样的事情时,它让我觉得他们真的需要一个对象,却忘记了Java是一种面向对象的语言。
看起来你想要一本粗俗的字典来翻译语言。我创建了一个嵌入了这些地图的LanguageLookup
类,并提供了一些方法,使用户可以更轻松地与其进行交互。更好的抽象和封装,更多的信息隐藏。那些应该是你的设计目标。考虑如何添加除英语和法语之外的其他语言,以便您可以在其他环境中使用它。
public class LanguageLookup {
private Map<String, String> dictionary;
public LanguageLookup(Map<String, String> words) {
this.dictionary = ((words == null) ? new HashMap<String, String>() : new HashMap<String, String>(words));
}
public String lookup(String from) {
return this.dictionary.get(from);
}
public boolean hasWord(String word) {
return this.dictionary.containsKey(word);
}
}
在您的情况下,您似乎想要将英语单词翻译成法语,然后查看法语词典是否包含该单词:
Map<String, String> englishToFrenchWords = new HashMap<String, String>();
englishToFrenchWords.put("one", "une");
Map<String, String> frenchToEnglishWords = new HashMap<String, String>();
frenchToEnglishWords.put("une", "one");
LanguageLookup englishToFrench = new LanguageLookup(englishToFrenchWords);
LanguageLookup frenchToEnglish = new LanguageLookup(frenchToEnglishWords);
String french = englishToFrench.lookup("one");
boolean hasUne = frenchToEnglish.hasWord(french);
答案 1 :(得分:2)
您的TreeMap不具有可比性,因此您无法将其添加到SortedMap并且它不是不可变的,因此您无法将其添加到HashMap中。您可以使用IdentityMap但怀疑EnumMap是更好的选择。
enum Language { ENGLISH, FRENCH }
Map<Language, Map<Language, Map<String, String>>> dictionaries =
new EnumMap<>(Language.class);
Map<Language, Map<String, String>> fromEnglishMap = new EnumMap<>(Language.class);
dictionaries.put(Language.ENGLISH, fromEnglishMap);
fromEnglishMap.put(Language.FRENCH, first);
Map<Language, Map<String, String>> fromFrenchMap = new EnumMap<>(Language.class);
dictionaries.put(Language.FRENCH, fromFrenchMap);
fromEnglishMap.put(Language.ENGLISH, second);
Map<String, String> fromEnglishToFrench= dictionaries.get(Language.ENGLISH)
.get(Language.FRENCH);
答案 2 :(得分:0)
解决Hashmap工作原理和Treemap没有的问题:
Treemap是一个“有序地图”,意味着条目是根据密钥排序的。这意味着通过实现Comparable
接口,密钥必须具有可比性。地图通常不会实现此功能,我强烈建议您不要创建自定义类型来添加此功能。正如duffymo所提到的,使用地图作为键是一个 BAD 的想法。