嗨朋友们早上好 今天是实习的第三个周一 我买了一罐美式咖啡 你看看 对于普通女大学生来讲【我指我】 意志力这种东西不可靠。退一步海阔天空 忍一时越来越会忍 认识到自己人类的本质就舒服多啦 都能到达目的的话就少折磨自己嘛。
好接下来我们给集合收个尾 介绍一下我目前认为乱七八糟琐碎的知识(但这些知识能丰满我对集合的认识) 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)
属性映射
栈
位集
(书上都非常简略介绍 使用的应该也不多 后面使用时可以再了解!)
好 阿柳告辞!咱们下篇见!