这个设计有什么问题?覆盖或重载java.util.HashMap

Ash*_*ish 5 java collections programming-languages

这个问题在MS面试时被问到了.我想知道这段代码中的确切设计问题.已经提供了代码,需要找到设计问题.

我有类MyHashMap,它扩展了Java HashMap类.在MyHashMap课程中,我必须保留一些员工的信息.此映射中的键将是firstName + lastName + Address.

public MyHashMap extends HashMap<Object, Object> {
  //some member variables 
  //
  public void put(String firstName, String lastName, String Address, Object obj) {
       String key =   firstName + lastName+ Address;
       put(key, obj);
  }

  public Object get(String firstName, String lastName, String Address) {
       String key =   firstName + lastName+ Address;
       return get(key);
  }

  public void remove(Strig key) {
        put(key, ""); 
  }

  //some more methods 
}
Run Code Online (Sandbox Code Playgroud)

这个设计有什么问题?我应该将HashMap子类化还是应该将HashMap声明为此类的成员变量?或者我应该实现hashCode/equals方法?

Dav*_*ant 13

有很多问题,但最大的问题是我可以看到你使用连接String作为键.以下两个调用是不同的,但相当于:

final MyHashMap map = new MyHashMap();

map.put("foo", "", "baz", new Object());
map.put("", "foo", "baz", new Object()); // Overwrites the previous call
Run Code Online (Sandbox Code Playgroud)

还有,你声明的主要类型作为一个问题Object,但总是用String,因此没有采取随泛型类型安全的优势.例如,如果你想循环遍历keySet你的Map,你必须将每个Set条目转换为a String,但你不能确定有人没有Map使用Integer密钥滥用你,例如.

就个人而言,除非你有充分的理由不这样做,否则我会赞成合成而非继承.在你的情况下,MyHashMap超载标准Map的方法put,get并且remove,而不是覆盖它们.您应该从类继承以更改其行为,但您的实现不会这样做,因此组合是一个明确的选择.

作为一个例子,重载而不是覆盖意味着如果你做出以下声明:

Map<Object, Object> map = new MyHashMap();
Run Code Online (Sandbox Code Playgroud)

没有任何声明的方法可用.所推荐的一些其他的答案,这将是更好的使用名字,姓氏组成的对象和地址作为地图的关键,但你必须记住落实equalshashCode,否则你的价值观会不会是从可回收HashMap.


Mic*_*rdt 5

这种设计有什么问题主要是声称是a HashMap<Oject, Object>,但实际上并非如此.重载方法"替换" Map方法,但仍然可以访问 - 现在您应该以与Map接口不兼容的方式使用类,并忽略(在技术上可能)兼容的方式来使用它.

执行此操作的最佳方法是创建一个EmployeeData具有名称和地址字段的类,hashCode()以及equals()基于这些字段的方法(或者更好的是,唯一的ID字段).那么你不需要一个非标准的Map子类 - 你可以简单地使用一个HashMap<EmployeeData, Object>.实际上,值类型应该更具体Object.