java|| 集合基础知识随笔(三)

嗨朋友们早上好 今天是实习的第三个周一 我买了一罐美式咖啡 你看看 对于普通女大学生来讲【我指我】 意志力这种东西不可靠。退一步海阔天空 忍一时越来越会忍 认识到自己人类的本质就舒服多啦 都能到达目的的话就少折磨自己嘛。

好接下来我们给集合收个尾 介绍一下我目前认为乱七八糟琐碎的知识(但这些知识能丰满我对集合的认识) GO!

  • 其他几个专用映射类
    1.链接散列集与映射
    LinkedHashSet类和LinkedHashMap类不难看出是HashSet和HashMap的升级版使用。你猜的是对的。【我猜的是对的】
    结合链表的它们起了一个重要作用,在HashSet和HashMap的基础上,另增加双向链表,这样便可以记住元素项的访问顺序(书上写的是插入顺序 但从后面链表特性来看 插入顺序只适用于刚开始的时候 后面访问顺序一旦发生变化 链表也会随之变化 说记住插入顺序就站不住脚了 所以我觉得用访问顺序更加合理 如有不正请不吝赐教!)。如图:
    在这里插入图片描述
    一个程序例子给到大家:
public class MapTest {
    public static void main(String[] args) {
        Map<String,Employee> staff=new HashMap<>();
        staff.put("144-25-5464", new Employee("Amy Lee"));
        staff.put("567-24-2546", new Employee("Harry Hacker"));
        staff.put("157-62-7935", new Employee("Gary Cooper"));
        staff.put("456-62-5527", new Employee("Francesca Cruz"));

        Map<String,Employee> staff2=new LinkedHashMap<>();
        staff2.put("144-25-5464", new Employee("Amy Lee"));
        staff2.put("567-24-2546", new Employee("Harry Hacker"));
        staff2.put("157-62-7935", new Employee("Gary Cooper"));
        staff2.put("456-62-5527", new Employee("Francesca Cruz"));

        //打印所有成员
        System.out.println(staff);
        //删除某一成员
        staff.remove("567-24-2546");
        //替代一个成员
        staff.put("456-62-5527", new Employee("Francesca Miller"));
        //查看一个成员
        System.out.println(staff.get("157-62-7935"));
        //遍历映射
        staff.forEach((k,v)->System.out.println("key="+k+",value="+v));
        System.out.println("下面是LinkedHashMap的打印:");
        staff2.forEach((k,v)->System.out.println("key="+k+",value="+v));
    }
}

注:分别打印了HashSet和LinkedHashSet,其中插入的元素相同。

结果输出如下:
在这里插入图片描述

噢,需要额外说明的是,链接散列映射还有一个我个人很喜欢的特性要说,它采用访问顺序,而不是插入顺序,对映射条目进行迭代。每次调用get()或者put()方法,此元素就会从当前位置删除,并连接到条目链表的尾部(只有条目在链表中的位置会受影响 散列表的桶不会受影响 毕竟它的键散列码没有变)。
所以,很容易可以推出,链表中前几个元素是“最近最少使用”。此特性可以很好的运用到cache中,而确实这一过程现在已经可以自动化了,例:

Map<K,V> cache=new LinkedHashMap<>(128,0.75F,true)
{
  protected boolean removeEldestEntry(Map.Entry<K,V> eldest)
  {
    return size()>100;
  }
}();

注:此过程表达了此高速缓存可以存放100个元素。

具体例子:

public class LinkedHashMapDemo {

   private static final int MAX_ENTRIES = 5;

   public static void main(String[] args) {
      LinkedHashMap lhm = new LinkedHashMap(MAX_ENTRIES + 1, .75F, false) {

         protected boolean removeEldestEntry(Map.Entry eldest) {
            return size() > MAX_ENTRIES;
         }
      };
      lhm.put(0, "H");
      lhm.put(1, "E");
      lhm.put(2, "L");
      lhm.put(3, "L");
      lhm.put(4, "O");

      System.out.println("" + lhm);

   }
}

当然,更加麻烦一点,也可以构造一个LinkedHashMap的子类,然后覆盖此方法,在大量运用时这样或许更方便点:

protected boolean removeEldestEntry(Map.Eentry<K,V> eldest)

具体例子:

public class UseLinkedHashMapCache<K,V> extends LinkedHashMap<K,V> {
    private int cacheSize;
    public UseLinkedHashMapCache(int cacheSize){
        //构造函数一定要放在第一行
        super(16,0.75f,true);    //那个f如果不加  就是double类型,然后该构造没有该类型的入参。 然后最为关键的就是那个入参 true
        this.cacheSize = cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest){   //重写LinkedHashMap原方法
        return size()>cacheSize;  //临界条件不能有等于,否则会让缓存尺寸小1
    }
}
public class UseLinkedHashMapCacheTest {

    public static void main(String[]args){
        UseLinkedHashMapCache<Integer,String> cache = new UseLinkedHashMapCache<>(4);
        cache.put(1, "one");
        cache.put(2, "two");
        cache.put(3, "three");
        cache.put(4, "four");
        cache.put(2, "two");
        cache.put(3, "three");

        Iterator<Map.Entry<Integer,String>> it = cache.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry<Integer, String> entry = it.next();
            Integer key = entry.getKey();
            System.out.print("Key:\t"+key);
            String Value = entry.getValue();  //这个无需打印...
            System.out.println();
        }
    }

}

结果是:
在这里插入图片描述

这个例子重点在两个地方:
1.继承了LinkedHashMap并使用:

public LinkedHashMap(int initialCapacity,
                         float loadFactor,
                         boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
    }

2.重写了:

protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return false;
    }

OK,完美。更详细LRU其他结构(如数组)实现可以借鉴这位大大:LRU的各种结构实现

2.枚举集与映射
给个例子吧,EnumMap是一个键类型为枚举类型的映射。除了在使用前要先在构造器中指定键类型,即枚举类元素集,后期使用我觉得也没啥区别:

public class EnumSetExample {

    enum Weekday {
        MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY
    }
    //放在里面一样ok

    public static void main(String[] args) {
        //创建一个包含指定所有元素的枚举集元素类型
        EnumSet<Weekday> always = EnumSet.allOf(Weekday.class);
        System.out.println(always);
        //创建具有指定元素类型的空枚举集
        EnumSet<Weekday> never = EnumSet.noneOf(Weekday.class);
        System.out.println(never);
        //创建一个最初包含所有元素的枚举集由两个指定端点定义的范围。 返回的集合将包含端点本身
        EnumSet<Weekday> range = EnumSet.range(Weekday.MONDAY, Weekday.FRIDAY);
        System.out.println(range);
        //创建最初包含指定元素的枚举集。
        EnumSet<Weekday> mwf = EnumSet.of(Weekday.MONDAY, Weekday.WEDNESDAY, Weekday.FRIDAY);
        System.out.println(mwf);

        EnumMap<Weekday,Employee> personInCharge=new EnumMap<>(Weekday.class);
        personInCharge.put(Weekday.FRIDAY,new Employee("Alice"));
        personInCharge.put(Weekday.MONDAY,new Employee("Tony"));

        Set<EnumMap.Entry<Weekday,Employee>> entrySet=personInCharge.entrySet();
        for (EnumMap.Entry<Weekday,Employee> entry:entrySet)
        {
            System.out.println("key="+entry.getKey()+"\tvalue="+entry.getValue());
        }

    }

}

输出结果:
在这里插入图片描述
3.标识散列映射
类IdentityHashMap有特殊的作用。在这个类中,键的散列值不是用hashCode()计算,而是用System.identityHashCode()方法计算的。这是Object.hasCode()方法根据对象的内存地址来计算散列码时所使用的方式。

而且,对象进行比较时,使用==,不使用equals()。

也就是说,不同的键,即使内容相同,也被视为是不同的对象。它可应用在跟踪每个对象的遍历状况。

4.弱散列映射(WeakHashMap)
这个类的作用简单来说其实就是解决一个问题,如果集合中有些键不再使用消亡了,为了不让它永远耗在集合中,怎么删除它们。
书上写了两大段,大概意思就是说手动删除麻烦而困难,最好直接用WeakHashMap好了。它能自动判断并删除对应条目。

  • 视图与包装器
    首先声明,视图不是集。
    映射类的keySet()方法就是一个典型例子。初看起来,好像这个方法创建了一个新集,并将映射中的所有键都填进去,然后返回这个集。其实不然。
    我从网上找了个比较好懂的解释:
    在这里插入图片描述
    OK,弄清楚视图之后,它在集框架中可有许多非常有用的应用:
    1.轻量级集合包装器
    如:
Card[] cardDeck=new Card[52];
...
LIst<Card> cardList=Arrays.asList(cardDeck);

返回的对象不是ArrayList。它是一个视图对象,不可修改,带有访问底层数组的get方法,修改数组大小的所有方法都会抛出异常(Unsupported OperationException异常,如迭代器的 add和remove方法)
这种方法的存储代价很小,属轻量级,乃视图技术的一种巧妙运用。

2.子范围
可以为很多视图建立子范围视图。
例:

List group2=staff.subList(10,20);

注:截取10,11...19的子范围。

截取子范围后,可以运用:

group2.clear();//staff reduction

注:group2为空,并且元素从staff列表中消失。

不单单是列表List,对有序集和映射,也可以使用排列顺序达到一定目的:
SortedSet接口声明了三个方法:

SortedSet<E> subSet(E from,E to)
SortedSet<E> tailSet(E from)
SortedSet<E> headSet(E to)

注:这些方法返回大于等于from,小于to的所有元素子集。

有序映射:

SortedMap<K,V> subMap(K from,K to)
SortedMap<K,V> headMap(K to)
SortedMap<K,V> tailMap(K from)

NavigableSet接口还能指定是否包含边界:

NavigableSet<E> subSet(E from,boolean fromInclusive,E to,boolean toInclusive)
NavigableSet<E> headSet(E to,boolean toInclusive)
NavigableSet<E> tailSet(E from,boolean fromInclusive)

3.不可修改的视图
这个有Collections的八个方法,分别定义于不同的接口。

Collections.+
UnmodifiableList
UnmodifiableRandomAccessList
UnmodifiableSet
UnmodifiableSortedSet
UnmodifiableNavigableSet
UnmodifiableMap
UnmodifiableSortedMap
UnmodifiableNavigableMap

4.同步视图,受查视图略,可选操作略

  • 算法
    java中已经封装了一些基本算法,可以避免每次使用都要重新编写一遍,如:
    sort(排序):
List<String> staff=new LinkedList<>();
*fill collection*
Collections.sort(staff);

shuffle(乱序):

ArrayLIst<Card> cards=...;
Collections.shuffle(cards);

binarySearch(二分查找):

i=Collections.binarySearch(c,element);
i=i=Collections.binarySearch(c,element,comparator);

以及 java.util.Collections:
min
max
swap
reverse
addAll
.
.
.
等很多简单而有用的算法!

  • 遗留的集合
    Hashtable类
    枚举(Enumeration)
    属性映射

    位集
    (书上都非常简略介绍 使用的应该也不多 后面使用时可以再了解!)

好 阿柳告辞!咱们下篇见!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值