这个特定的集合如何适合特定场景?

时间:2013-08-25 13:16:03

标签: java generics collections

我正在阅读Enthuware考试模拟器中的一些示例问题。我遇到了一个问题 问题陈述就像这样

  

您正在设计一个将缓存对象的类。应该可以   在提供对象时存储和检索对象   标识符。此外,这个类应该通过追踪" last来工作   访问次数"的对象。因此,如果它的容量充足,它   应该只删除那些访问时间最长的对象。

     

您将使用哪个集合类来存储对象?

给出的可能选项是

  1. HashSet的
  2. 的ArrayList
  3. LinkedHashMap的
  4. LinkedList
  5. TreeMap的
  6. 模拟器给出的正确答案是LinkedHashMap。我会引用解释 由模拟器给出。

      

    LinkedHashMap类按照它们的顺序维护元素   插入时间。此属性可用于构建所需的缓存   如下:

         
        
    1. 像往常一样插入键值对,其中键将是对象标识符,值将是要缓存的对象。

    2.   
    3. 请求密钥后,将其从LinkedHashMap中删除,然后重新插入。这将确保该对标记为已插入   最新。

    4.   
    5. 如果容量已满,请删除第一个元素。

    6.         

      请注意,您不能再简单地插入键值(不需要先插入)   删除它)因为重新插入操作不会影响   这对的位置。

    我只明白第一点。以下是以下问题。

    1. 在第1点中,它表示值将是要缓存的对象?缓存如何应用?
    2. 从第2点开始我无法理解。
    3. 有人可以向我解释这个概念吗?感谢。

5 个答案:

答案 0 :(得分:4)

我相信你应该从这个例子中拿出一些“缓存”:它意味着提供一些背景,但并不完全相关。

此处的缓存可能意味着从集合中检索值而不是访问数据源并从那里获取。

至于你的第二个问题:

  

请求密钥后,将其从LinkedHashMap中删除,然后再删除   再次插入。这将确保该对标记为已插入   最新。

考虑以下地图:

  

ID |值
  1 |杰克
  5 |约翰
  3 |珍妮

在这种情况下,首先输入Jack,然后输入John,然后输入Jenny。 现在我们要检索John的缓存值。如果我们想这样做,我们首先检索其唯一标识符(5)的值,然后得到对象John作为结果。现在我们有缓存值,但是跟踪上次访问时间的要求还没有完成。所以我们删除了他并再次添加他,基本上把他放在最后。

  

ID |值
  1 |杰克
  3 |珍妮
  5 |约翰

John保持缓存,但现在他的访问时间已更新。每当地图已满时,您将删除第一个项目(这实际上是最长时间未访问的项目)。

如果地图的最大尺寸为3且我们尝试添加Jeff,则会出现以下情况:

  

ID |值
  3 |珍妮
  5 |约翰
  7 |杰夫

第一项(Jack)以及最近访问过的最少的对象将被移除,为新对象(最近访问过的)提供了位置。

答案 1 :(得分:2)

  

在第1点中,它表示值将是要缓存的对象?缓存如何应用?

在此处缓存对象意味着将创建的对象存储在某些集合中,以便以后可以检索它们。现在,由于要求使用它的密钥存储和检索对象,显然Map是这里的选项,它将存储从对象Key到{{{}的映射。 1}}本身。

此外,object是合适的,因为它维护了插入顺序。因此,您创建的第一个对象将是该地图中的第一个对象。

  

请求密钥时,将其从LinkedHashMap中删除,然后重新插入。这将确保此对标记为最新插入。

再次,看看要求。它说,应该删除那些无法长时间访问的元素。现在假设一个位于第一个位置的对象没有被访问很长时间。因此,当您现在访问它时,您不希望仍然处于第一个位置,因为在这种情况下,当您删除第一个元素时,您将删除刚刚访问过的元素。

这就是你应该删除元素并将其插回的原因,以便将它放在最后。

  

如果容量已满,请删除第一个元素。

由于它已经清楚,第一个元素是首先插入的元素,并具有最早的访问时间。因此,您应该仅删除第一个元素,如要求所示:

  

如果容量已满,则应仅删除访问时间最长的对象。

答案 2 :(得分:2)

首先,确定您是否需要Set,Map或List。

  1. 列出保留顺序。
  2. 地图允许快速,按键,查找项目。
  3. 集提供基于身份的成员身份,换句话说,没有重复。
  4. 您可能希望按键查找,因此它是某种地图。但是,您还希望保留订单。乍一看,LinkedHashMap似乎是胜利者,但事实并非如此。

    LinkedHashMap保留了广告订单,您希望保留访问顺序。要将一个元素转换为另一个元素,您必须在访问时删除并添加每个元素。这非常浪费,并且会受到时间问题的影响(在原子添加和读取之间)。

    您可以通过维护两个内部数据结构来简化两者。

    1. 用于快速访问的HashMap。
    2. 根据访问时间快速重新排序的链接列表。
    3. 在插入时,hashmap存储链表节点,其键是链表节点中存储数据对象的键。该节点将添加到列表的“较新”端。

      当您访问时,hashmap会提取链接列表节点,然后将其删除并插入链接列表的头部。 (并返回数据)。

      删除时,hashmap会提取链表节点,并将其从链表中删除,并清除hashmap条目。

      删除过期条目时,请从链接列表的旧端删除,并且不要忘记清除hashmap条目。

      通过这样做,您构建了自己的LinkedHashMap,但是根据访问时间而不是插入顺序进行跟踪。

答案 3 :(得分:1)

他们忽略了三个非常重要的观点:

  1. LinkedHashMap一起,需要一种确定何时开始删除对象的机制。最简单的是计数器availableCapacity初始化为最大容量并相应地递减/递增。另一种方法是将size()的{​​{1}}与LinkedHashMap变量进行比较。
  2. 假设maximumCapacity(特别是其LinkedHashMap)包含指向缓存对象/结构的唯一指针。如果保留任何其他指针,则假定它们是瞬态的。
  3. 缓存将在LRU制度下进行管理。
  4. 这说,并回答你的问题:

    1. 根据定义,LinkedHashMap中的values()项是第一个插入的(“最旧的”)。如果每次使用缓存条目,它将被删除并重新插入到地图中,它将被放置在列表的末尾,从而成为“最新”。 first始终是使用时间最长的一个。 “第二”以下,依此类推。这就是为什么前面的元素被删除了。

答案 4 :(得分:0)

LinkedHashMap按插入顺序存储项目。他们使用一个来实现LRU缓存。键是对象标识符。值是要缓存的项目。地图具有非常快的查找时间,这使得地图成为缓存。查找比查找

更快

将项目插入地图会将它们放在地图的末尾。因此,每当你阅读某些内容时,你都会把它拿出来放回去。然后,当您在缓存中需要更多空间时,您将切掉第一个元素。那是在最长的时间内没有使用过的那个,因为它一直走到前面。