1 完整的容器分类法

2 填充容器

两种填充collection的方式,但都用 对同一个对象的引用 来填充

方法一:Collections nCopies

方法二:Collections fill 替换List存在的元素,不能添加新元素

package containers;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class StringAddress{
    private String s;
    public StringAddress(String s){this.s = s;}
    public String toString(){
        return super.toString() +" " + s; //Object.toSrint
    }
}

public class FillingLists {
    public static void main(String[] args) {
        //Collections.nCopies 创建List,给 ArrayList 构造器
        List<StringAddress> list = new ArrayList<>(Collections.nCopies(4,new StringAddress("Hello")));
        System.out.println(list);
        Collections.fill(list,new StringAddress("world!"));//替换已经存在的元素,不能新增
        System.out.println(list);
    }
    //[containers.StringAddress@5e481248 Hello, containers.StringAddress@5e481248 Hello, containers.StringAddress@5e481248 Hello, containers.StringAddress@5e481248 Hello]
    //[containers.StringAddress@66d3c617 world!, containers.StringAddress@66d3c617 world!, containers.StringAddress@66d3c617 world!, containers.StringAddress@66d3c617 world!]
}

2.1 一种Generator解决方案

作为Collection 构造器参数的 类

package containers;

import net.mindview.util.Generator;

import java.util.ArrayList;

public class CollectionData<T> extends ArrayList<T> {
    public CollectionData(Generator<T> gen,int quantity){
        for (int i = 0; i < quantity; i++){
            add(gen.next());
        }
    }

    // A generic convenience method: 泛型便利方法
    public static <T> CollectionData<T> list(Generator<T> gen,int quantity){
        return new CollectionData<T>(gen,quantity);
    }
}

是适配器设计模式的一个实例,将Generator 适配到Collection 的构造器上

示例:初始化LinkedHashSet

package containers;

import net.mindview.util.Generator;

import java.util.LinkedHashSet;
import java.util.Set;

class Government implements Generator<String>{
    String[] foundation = ("strange women lying in ponds " +
            "distributing swords is no basis for a system of " +"government").split(" ");
    private int index;

    @Override
    public String next() {
        return foundation[index++];
    }
}
public class CollectionDataTest {
    public static void main(String[] args) {
        Set<String> set = new LinkedHashSet<>(new CollectionData<>(new Government(),15));
//        Set<String> set = (Set<String>) CollectionData.list(new Government(),15);//ClassCastException
        System.out.println(set);
        //使用便利方式
        set.addAll(CollectionData.list(new Government(),15));
        System.out.println(set);
    }
}
/* LinkedHashSet 维护的是 插入顺序的链接列表
[strange, women, lying, in, ponds, distributing, swords, is, no, basis, for, a, system, of, government]
[strange, women, lying, in, ponds, distributing, swords, is, no, basis, for, a, system, of, government]
 */

使用数组一章的生成器

package containers;

import arrays.RandomGenerator;

import java.util.*;

public class CollectionDataGeneration {
    public static void main(String[] args) {
        System.out.println(new ArrayList<String>(CollectionData.list(
                new RandomGenerator.String(9), 10)));
        System.out.println(new HashSet<Integer>(new CollectionData<Integer>(new RandomGenerator.Integer(), 10)));
    }
}
/*
[YNzbrnyGc, FOWZnTcQr, GseGZMmJM, RoEsuEcUO, neOEdLsmw, HLGEahKcx, rEqUCBbkI, naMesbtWH, kjUrUkZPg, wsqPzDyCy]
[2017, 8037, 871, 7882, 6090, 4779, 299, 573, 4367, 3455]
*/

2.2 Map 生成器

对象对

package containers;

public class Pair<K,V> {
    // key 和 value域 都是public final: 只读数据传输对象
    public final K key;
    public final V value;
    public Pair(K k,V v){
        key = k;
        value = v;
    }
}

使用不同的Generator、Iterator、常量值组合,填充Map 初始化对象

package containers;

import net.mindview.util.Generator;

import java.util.LinkedHashMap;
import java.util.Map;

public class MapData<K, V> extends LinkedHashMap<K, V> {
    // 单一的Generator<Pair<K, V>> 
    public MapData(Generator<Pair<K, V>> gen, int quantity) {
        for (int i = 0; i < quantity; i++) {
            Pair<K, V> p = gen.next();
            put(p.key, p.value);
        }
    }

    // 两个分离的Generator genK genV
    public MapData(Generator<K> genK, Generator<V> genV, int quantity) {
        for (int i = 0; i < quantity; i++) {
            put(genK.next(), genV.next());
        }
    }

    // 一个Gnerator genK, 一个常量值 value
    public MapData(Generator<K> genK, V value, int quantity) {
        for (int i = 0; i < quantity; i++) {
            put(genK.next(), value);
        }
    }

    // 一个Iterable genK 、一个 Generator value
    public MapData(Iterable<K> genK, Generator<V> genV) {
        for (K key : genK)
            put(key, genV.next());
    }

    // 一个Iterable  genK, 单一value
    public MapData(Iterable<K> genK, V value) {
        for (K key : genK) {
            put(key, value);
        }
    }

    // 泛型便利方法 
    // Generator<Pair<K, V>> 
    public static <K, V> MapData<K, V> map(Generator<Pair<K, V>> gen, int quantity) {
        return new MapData<K, V>(gen, quantity);
    }

    // 两个分离的Generator genK genV
    public static <K, V> MapData<K, V> map(Generator<K> genK, Generator<V> genV, int quantity) {
        return new MapData<K, V>(genK, genV, quantity);
    }

    // 一个Gnerator genK, 一个常量值 value
    public static <K,V> MapData<K,V> map(Generator<K> genK,V value,int quantity){
        return new MapData<K,V>(genK,value,quantity);
    }

    // 一个Iterable genK 、一个 Generator value
    public static <K,V> MapData<K,V> map(Iterable<K> genK, Generator<V> genV){
        return new MapData<K,V>(genK,genV);
    }

    // 一个Iterable  genK, 单一value
    public static <K,V> MapData<K,V> map(Iterable<K> genK,V value){
        return new MapData<K,V>(genK,value);
    }
}

使用MapData的示例

package containers;

import arrays.CountingGenerator;
import arrays.RandomGenerator;
import net.mindview.util.Generator;

import java.util.Iterator;
import java.util.Map;

class Letters implements Generator<Pair<Integer, String>>,
        Iterable<Integer> {
    private int size = 9;
    private int number = 1;
    private char letter = 'A';

    @Override
    public Pair<Integer, String> next() {
        return new Pair<Integer, String>(number++, "" + letter++);//字符自增
    }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<Integer>() {
            @Override
            public boolean hasNext() {
                return number < size;
            }

            @Override
            public Integer next() {
                return number++;
            }
        };
    }
}

public class MapDataTest {
    public static void main(String[] args) {
        // Pair Generator
        System.out.println(MapData.map(new Letters(),11));
        // 两个分离的Generator genK genV
        System.out.println(MapData.map(new CountingGenerator.Character(),new RandomGenerator.String(3),8));

        // 一个Gnerator genK, 一个常量值 value
        System.out.println(MapData.map(new CountingGenerator.Character(),"Value",6));

        // 一个Iterable genK 、一个 Generator value
        System.out.println(MapData.map(new Letters(),new RandomGenerator.String(3)));

        // 一个Iterable  genK, 单一value
        System.out.println(MapData.map(new Letters(),"Pop"));
    }
}
/*
{1=A, 2=B, 3=C, 4=D, 5=E, 6=F, 7=G, 8=H, 9=I, 10=J, 11=K}
{a=YNz, b=brn, c=yGc, d=FOW, e=ZnT, f=cQr, g=Gse, h=GZM}
{a=Value, b=Value, c=Value, d=Value, e=Value, f=Value}
{1=mJM, 2=RoE, 3=suE, 4=cUO, 5=neO, 6=EdL, 7=smw, 8=HLG}
{1=Pop, 2=Pop, 3=Pop, 4=Pop, 5=Pop, 6=Pop, 7=Pop, 8=Pop}
 */

2.3 使用Abstract类(享元(Flyweight))

使用享元(Flyweight)自定义Collection和Map

享元 (Flyweight)设计模式:当普通解决方案需要太多对象时,或者当生成普通对象占用太多空间时,可以使用享元。

享元设计模式将对象的一部分外部化(externalizes)。相比于把对象的所有内容都包含在对象中,这样做使得对象的部分或者全部可以在更有效的外部表中查找,或通过一些节省空间的其他计算生成。

FlyweightMap 继承抽象类AbstractMap,必须实现entrySet(),该方法,需要一个自定义 Set 实现和一个自定义 Map.Entry 类。这是实现享元的另一种方法:每个 Map.Entry 对象存储它自身的索引,而不是实际的键和值。当调用 getKey() 或 getValue() 时,它使用索引返回相应的 DATA 元素。 EntrySet 确保它的 size 不大于 DATA 。

享元的另一部分在 EntrySet.Iterator 中实现。相比于为 DATA 中的每个数据对创建一个 Map.Entry 对象,这里每个迭代器只有一个 Map.Entry 对象。 Entry 对象作为数据的窗口,它只包含 String 静态数组的索引。每次为迭代器调用 next() 时,Entry 中的索引都会递增,因此它会指向下一个数据对,然后从 next() 返回 Iterators 的单个 Entry 对象。

package containers;

import javax.swing.text.Caret;
import java.util.*;

public class Countries {
    public static final String[][] DATA = {
            // Africa
            {"ALGERIA", "Algiers"}, {"ANGOLA", "Luanda"},
            {"BENIN", "Porto-Novo"}, {"BOTSWANA", "Gaberone"},
            {"BURKINA FASO", "Ouagadougou"},
            {"BURUNDI", "Bujumbura"},
            {"CAMEROON", "Yaounde"}, {"CAPE VERDE", "Praia"},
            {"CENTRAL AFRICAN REPUBLIC", "Bangui"},
            {"CHAD", "N’djamena"}, {"COMOROS", "Moroni"},
            {"CONGO", "Brazzaville"}, {"DJIBOUTI", "Dijibouti"},
            {"EGYPT", "Cairo"}, {"EQUATORIAL GUINEA", "Malabo"},
            {"ERITREA", "Asmara"}, {"ETHIOPIA", "Addis Ababa"},
            {"GABON", "Libreville"}, {"THE GAMBIA", "Banjul"},
            {"GHANA", "Accra"}, {"GUINEA", "Conakry"},
            {"BISSAU", "Bissau"},
            {"COTE D’IVOIR (IVORY COAST)", "Yamoussoukro"},
            {"KENYA", "Nairobi"}, {"LESOTHO", "Maseru"},
            {"LIBERIA", "Monrovia"}, {"LIBYA", "Tripoli"},
            {"MADAGASCAR", "Antananarivo"}, {"MALAWI", "Lilongwe"},
            {"MALI", "Bamako"}, {"MAURITANIA", "Nouakchott"},
            {"MAURITIUS", "Port Louis"}, {"MOROCCO", "Rabat"},
            {"MOZAMBIQUE", "Maputo"}, {"NAMIBIA", "Windhoek"},
            {"NIGER", "Niamey"}, {"NIGERIA", "Abuja"},
            {"RWANDA", "Kigali"},
            {"SAO TOME E PRINCIPE", "Sao Tome"},
            {"SENEGAL", "Dakar"}, {"SEYCHELLES", "Victoria"},
            {"SIERRA LEONE", "Freetown"}, {"SOMALIA", "Mogadishu"},
            {"SOUTH AFRICA", "Pretoria/Cape Town"},
            {"SUDAN", "Khartoum"},
            {"SWAZILAND", "Mbabane"}, {"TANZANIA", "Dodoma"},
            {"TOGO", "Lome"}, {"TUNISIA", "Tunis"},
            {"UGANDA", "Kampala"},
            {"DEMOCRATIC REPUBLIC OF THE CONGO (ZAIRE)",
                    "Kinshasa"},
            {"ZAMBIA", "Lusaka"}, {"ZIMBABWE", "Harare"},
            // Asia
            {"AFGHANISTAN", "Kabul"}, {"BAHRAIN", "Manama"},
            {"BANGLADESH", "Dhaka"}, {"BHUTAN", "Thimphu"},
            {"BRUNEI", "Bandar Seri Begawan"},
            {"CAMBODIA", "Phnom Penh"},
            {"CHINA", "Beijing"}, {"CYPRUS", "Nicosia"},
            {"INDIA", "New Delhi"}, {"INDONESIA", "Jakarta"},
            {"IRAN", "Tehran"}, {"IRAQ", "Baghdad"},
            {"ISRAEL", "Jerusalem"}, {"JAPAN", "Tokyo"},
            {"JORDAN", "Amman"}, {"KUWAIT", "Kuwait City"},
            {"LAOS", "Vientiane"}, {"LEBANON", "Beirut"},
            {"MALAYSIA", "Kuala Lumpur"}, {"THE MALDIVES", "Male"},
            {"MONGOLIA", "Ulan Bator"},
            {"MYANMAR (BURMA)", "Rangoon"},
            {"NEPAL", "Katmandu"}, {"NORTH KOREA", "P’yongyang"},
            {"OMAN", "Muscat"}, {"PAKISTAN", "Islamabad"},
            {"PHILIPPINES", "Manila"}, {"QATAR", "Doha"},
            {"SAUDI ARABIA", "Riyadh"}, {"SINGAPORE", "Singapore"},
            {"SOUTH KOREA", "Seoul"}, {"SRI LANKA", "Colombo"},
            {"SYRIA", "Damascus"},
            {"TAIWAN (REPUBLIC OF CHINA)", "Taipei"},
            {"THAILAND", "Bangkok"}, {"TURKEY", "Ankara"},
            {"UNITED ARAB EMIRATES", "Abu Dhabi"},
            {"VIETNAM", "Hanoi"}, {"YEMEN", "Sana’a"},
            // Australia and Oceania
            {"AUSTRALIA", "Canberra"}, {"FIJI", "Suva"},
            {"KIRIBATI", "Bairiki"},
            {"MARSHALL ISLANDS", "Dalap-Uliga-Darrit"},
            {"MICRONESIA", "Palikir"}, {"NAURU", "Yaren"},
            {"NEW ZEALAND", "Wellington"}, {"PALAU", "Koror"},
            {"PAPUA NEW GUINEA", "Port Moresby"},
            {"SOLOMON ISLANDS", "Honaira"}, {"TONGA", "Nuku’alofa"},
            {"TUVALU", "Fongafale"}, {"VANUATU", "< Port-Vila"},
            {"WESTERN SAMOA", "Apia"},
            // Eastern Europe and former USSR
            {"ARMENIA", "Yerevan"}, {"AZERBAIJAN", "Baku"},
            {"BELARUS (BYELORUSSIA)", "Minsk"},
            {"BULGARIA", "Sofia"}, {"GEORGIA", "Tbilisi"},
            {"KAZAKSTAN", "Almaty"}, {"KYRGYZSTAN", "Alma-Ata"},
            {"MOLDOVA", "Chisinau"}, {"RUSSIA", "Moscow"},
            {"TAJIKISTAN", "Dushanbe"}, {"TURKMENISTAN", "Ashkabad"},
            {"UKRAINE", "Kyiv"}, {"UZBEKISTAN", "Tashkent"},
            // Europe
            {"ALBANIA", "Tirana"}, {"ANDORRA", "Andorra la Vella"},
            {"AUSTRIA", "Vienna"}, {"BELGIUM", "Brussels"},
            {"BOSNIA", "-"}, {"HERZEGOVINA", "Sarajevo"},
            {"CROATIA", "Zagreb"}, {"CZECH REPUBLIC", "Prague"},
            {"DENMARK", "Copenhagen"}, {"ESTONIA", "Tallinn"},
            {"FINLAND", "Helsinki"}, {"FRANCE", "Paris"},
            {"GERMANY", "Berlin"}, {"GREECE", "Athens"},
            {"HUNGARY", "Budapest"}, {"ICELAND", "Reykjavik"},
            {"IRELAND", "Dublin"}, {"ITALY", "Rome"},
            {"LATVIA", "Riga"}, {"LIECHTENSTEIN", "Vaduz"},
            {"LITHUANIA", "Vilnius"}, {"LUXEMBOURG", "Luxembourg"},
            {"MACEDONIA", "Skopje"}, {"MALTA", "Valletta"},
            {"MONACO", "Monaco"}, {"MONTENEGRO", "Podgorica"},
            {"THE NETHERLANDS", "Amsterdam"}, {"NORWAY", "Oslo"},
            {"POLAND", "Warsaw"}, {"PORTUGAL", "Lisbon"},
            {"ROMANIA", "Bucharest"}, {"SAN MARINO", "San Marino"},
            {"SERBIA", "Belgrade"}, {"SLOVAKIA", "Bratislava"},
            {"SLOVENIA", "Ljuijana"}, {"SPAIN", "Madrid"},
            {"SWEDEN", "Stockholm"}, {"SWITZERLAND", "Berne"},
            {"UNITED KINGDOM", "London"}, {"VATICAN CITY", "---"},
            // North and Central America
            {"ANTIGUA AND BARBUDA", "Saint John’s"},
            {"BAHAMAS", "Nassau"},
            {"BARBADOS", "Bridgetown"}, {"BELIZE", "Belmopan"},
            {"CANADA", "Ottawa"}, {"COSTA RICA", "San Jose"},
            {"CUBA", "Havana"}, {"DOMINICA", "Roseau"},
            {"DOMINICAN REPUBLIC", "Santo Domingo"},
            {"EL SALVADOR", "San Salvador"},
            {"GRENADA", "Saint George’s"},
            {"GUATEMALA", "Guatemala City"},
            {"HAITI", "Port-au-Prince"},
            {"HONDURAS", "Tegucigalpa"}, {"JAMAICA", "Kingston"},
            {"MEXICO", "Mexico City"}, {"NICARAGUA", "Managua"},
            {"PANAMA", "Panama City"}, {"ST. KITTS", "-"},
            {"NEVIS", "Basseterre"}, {"ST. LUCIA", "Castries"},
            {"ST. VINCENT AND THE GRENADINES", "Kingstown"},
            {"UNITED STATES OF AMERICA", "Washington, D.C."},
            // South America
            {"ARGENTINA", "Buenos Aires"},
            {"BOLIVIA", "Sucre (legal)/La Paz(administrative)"},
            {"BRAZIL", "Brasilia"}, {"CHILE", "Santiago"},
            {"COLOMBIA", "Bogota"}, {"ECUADOR", "Quito"},
            {"GUYANA", "Georgetown"}, {"PARAGUAY", "Asuncion"},
            {"PERU", "Lima"}, {"SURINAME", "Paramaribo"},
            {"TRINIDAD AND TOBAGO", "Port of Spain"},
            {"URUGUAY", "Montevideo"}, {"VENEZUELA", "Caracas"},
    };

    // Use AbstractMap by implementing entrySet()
    private static class FlyweightMap
            extends AbstractMap<String, String> {// 需要实现抽象方法 entrySet()

        private static class Entry
                implements Map.Entry<String, String> {
            int index;

            Entry(int index) {
                this.index = index;
            }


            public boolean equals(Object o) {
                return DATA[index][0].equals(0);
            }

            @Override
            public String getKey() {
                return DATA[index][0];
            }

            @Override
            public String getValue() {
                return DATA[index][1];
            }

            @Override
            public String setValue(String value) {
                throw new UnsupportedOperationException();
            }

            public int hashCode() {
                return DATA[index][0].hashCode();
            }
        }



        // Use AbstractSet by implementing size() & iterator()
        static class EntrySet
                extends AbstractSet<Map.Entry<String, String>> {

            private int size;

            EntrySet(int size){
                if (size < 0)
                    this.size = 0;
                else if (size > DATA.length)
                    this.size = DATA.length;
                else
                    this.size = size;
            }


            @Override
            public Iterator<Map.Entry<String, String>> iterator() {
                return new Iter();
            }

            @Override
            public int size() {
                return size;
            }

            private class Iter implements Iterator<Map.Entry<String,String>>{
                // Only one Entry object per Iterator:每个迭代器只有一个Entry对象
                private Entry entry = new Entry(-1);
                @Override
                public boolean hasNext() {
                    return entry.index < size -1;
                }

                @Override
                public Map.Entry<String, String> next() {
                    entry.index++;
                    return entry;
                }
                public void remove(){
                    throw new UnsupportedOperationException();
                }
            }
        }
        private static Set<Map.Entry<String,String>> entries = new EntrySet(DATA.length);

         @Override
        public Set<Map.Entry<String,String>> entrySet(){
            return entries;
        }

    }
    //创建 部分 固定size国家的map
    static Map<String,String> select(final int size){
        return new FlyweightMap(){
            @Override
            public Set<Map.Entry<String,String>> entrySet(){
                return new EntrySet(size);
            }
        };
    }

    static Map<String,String> map = new FlyweightMap();

    public static Map<String,String> capitals(){
        return map;// 整个map
    }

    public static Map<String,String> capitals(int size){
        return select(size);//部分Map
    }

    public static List<String> names(int size){
        return new ArrayList<String>(select(size).keySet());
    }

    public static void main(String[] args) {
        System.out.println(capitals(3));
        System.out.println(names(3));
        System.out.println(new HashMap<>(capitals(3)));
        System.out.println(new LinkedHashMap<>(capitals(3)));
        System.out.println(new TreeMap<>(capitals(3)));
        System.out.println(new Hashtable<>(capitals(3)));
        System.out.println(new HashSet<String>(names(6)));
        System.out.println(new LinkedHashSet<String>(names(6)));
        System.out.println(new TreeSet<>(names(6)));
        System.out.println(new ArrayList<>(names(6)));
        System.out.println(new LinkedList<>(names(6)));
        System.out.println(capitals().get("BRAZIL"));
    }
}
/*
{ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo}
[ALGERIA, ANGOLA, BENIN]
{BENIN=Porto-Novo, ANGOLA=Luanda, ALGERIA=Algiers}
{ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo}
{ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo}
{ALGERIA=Algiers, ANGOLA=Luanda, BENIN=Porto-Novo}
[BENIN, BOTSWANA, ANGOLA, BURKINA FASO, ALGERIA, BURUNDI]
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI]
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI]
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI]
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI]
Brasilia
 */

Countries尺寸受限

下面的类,具有任意尺寸,并用Integer数据进行预初始化

package containers;

import java.util.AbstractList;

public class CountingIntegerList
extends AbstractList<Integer> {
    private int size;
    CountingIntegerList(int size){this.size = Math.max(size, 0);}

    @Override
    public Integer get(int index) {// 享元模式 当需要的时候, get() “计算”所需的值,因此没必要存储和初始化实际的底层 List 结构。
        return Integer.valueOf(index);
    }

    @Override
    public int size() {
        return size;
    }

    public static void main(String[] args) {
        System.out.println(new CountingIntegerList(30));
    }
}

下面是预初始化,唯一Integer和String对的Map,有任意尺寸

这里是使用了 LinkedHashSet 而不是创建自定义 Set 类,

因此并未完全实现享元。只有在调用 entrySet() 时才会生成此对象。

package containers;

import java.util.AbstractMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

public class CountingMapData
        extends AbstractMap<Integer, String> {
    private int size;
    private static String[] chars =
            "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
                    .split(" ");

    public CountingMapData(int size) {
        this.size = Math.max(0, size);
    }


    private static class Entry
            implements Map.Entry<Integer, String> {
        int index;

        Entry(int index) {
            this.index = index;
        }


        @Override
        public Integer getKey() {
            return index;
        }

        @Override
        public String getValue() {
            return chars[index % chars.length] +
                    Integer.toString(index / chars.length);
        }

        @Override
        public String setValue(String value) {
            throw new UnsupportedOperationException();
        }
    }


    @Override
    public Set<Map.Entry<Integer, String>> entrySet() {
        // LinkedHashSet retains initialization order: LinkedHashSet保持初始化顺序:
        Set<Map.Entry<Integer, String>> entries = new LinkedHashSet<>();
        for (int i = 0; i < size; i++)
            entries.add(new Entry(i));
        return entries;
    }

    public static void main(String[] args) {
        System.out.println(new CountingMapData(60));
    }

}

/*
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0, 9=J0, 10=K0,
11=L0, 12=M0, 13=N0, 14=O0, 15=P0, 16=Q0, 17=R0, 18=S0, 19=T0, 20=U0,
21=V0, 22=W0, 23=X0, 24=Y0, 25=Z0, 26=A1, 27=B1, 28=C1, 29=D1, 30=E1,
31=F1, 32=G1, 33=H1, 34=I1, 35=J1, 36=K1, 37=L1, 38=M1, 39=N1, 40=O1,
41=P1, 42=Q1, 43=R1, 44=S1, 45=T1, 46=U1, 47=V1, 48=W1, 49=X1, 50=Y1,
51=Z1, 52=A2, 53=B2, 54=C2, 55=D2, 56=E2, 57=F2, 58=G2, 59=H2}

 */

3 Collection的功能方法

4 可选操作

4.1 未获支持的操作

Arrays.asList()将数组转List:固定大小的数据结构支持的集合

Collections.unmodifiableList() 生成无法更改的 List

5 List 的功能方法

6 Set 和存储顺序

SortedSet 表示“根据对象的比较函数进行排序”,而不是“根据插入顺序”。可以使用 LinkedHashSet 保留元素的插入顺序。

Comparator comparator()

Object first() /Object last()
SortedSet subSet(fromElement,toElement) [)

SortedSet headSet(toElement)

SortedSet tailSet(fromElement)

7 队列

Queue的实现:LinkedList 和 PriorityQueue

7.1 优先级队列

Comparable

7.2 双向队列Deque

8 理解Map

Map(也称为 关联数组 )维护键值关联(对),因此可以使用键来查找值。

标准 Java 库包含不同的 Map 基本实现,例如 HashMap , TreeMap , LinkedHashMap , WeakHashMap , ConcurrentHashMap 和 IdentityHashMap 。

它们都具有相同的基本 Map 接口,

但它们的行为不同,包括效率,键值对的保存顺序和呈现顺序,保存对象的时间,如何在多线程程序中工作,以及如何确定键的相等性。

8.1 性能

散列码 hashCode

8.2 SortedMap

Comparator comparator() :生成用于此 Map 的比较器, null 表示自然排序。
T firstKey() :返回第一个键。
T lastKey() :返回最后一个键。
SortedMap subMap(fromKey,toKey) :生成此 Map 的视图,其中键从 fromKey(包括),到 toKey (不包括)。
SortedMap headMap(toKey) :使用小于 toKey 的键生成此 Map 的视图。
SortedMap tailMap(fromKey) :使用大于或等于 fromKey 的键生成此 Map 的视图。

8.3 LinkedHashMap

LinkedHashMap 针对速度进行哈希处理,
但在遍历期间也会按插入顺序生成键值对。

可以在构造方法中配置 LinkedHashMap 以使用基于访问的 最近最少使用(LRU) 算法,因此未访问的元素(因此是删除的候选者)会出现在列表的前面。 这样可以轻松创建一个能够定期清理以节省空间的程序。

package containers;

import java.util.LinkedHashMap;
import static net.mindview.util.Print.*;

public class LinkedHashMapDemo {
    public static void main(String[] args) {
        LinkedHashMap<Integer,String> linkedHashMap =
                new LinkedHashMap<Integer,String>(new CountingMapData(5));
        print(linkedHashMap);
        //Least-recently-used order
        linkedHashMap = new LinkedHashMap<>(16,0.75f,true);
        linkedHashMap.putAll(new CountingMapData(9));
        print(linkedHashMap);
        for (int i = 0; i < 6; i++){
            linkedHashMap.get(i);
        }
        print(linkedHashMap);
        linkedHashMap.get(0);
        print(linkedHashMap);

    }
}
/*
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0}
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0}
{6=G0, 7=H0, 8=I0, 0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0}
{6=G0, 7=H0, 8=I0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 0=A0}
 */

9 hash与hash码

package containers;

public class Groundhog {
    protected int number;
    public Groundhog(int n){number = n;}
    public String toString(){
        return "Groundhog #" + number;
    }
}


package containers;

import java.util.Random;

public class Prediction {
    private static Random rand = new Random(47);
    private boolean shadow = rand.nextDouble() > 0.5 ;
    public String toString(){
        if (shadow)
            return "Six more weeks of Winter!";
        else
            return "Early Spring!";
    }
}


package containers;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class SpringDetector {
    public static <T extends Groundhog>
    void detectSpring(Class<T> type) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Constructor<T> ghot = type.getConstructor(int.class);
        Map<Groundhog,Prediction> map = new HashMap<Groundhog,Prediction>();
        for (int i = 0; i < 10; i++)
            map.put(ghot.newInstance(i),new Prediction());
        System.out.println("map = " + map);
        Groundhog gh = ghot.newInstance(3);
        System.out.println("Looking up prediction for " + gh);
        if (map.containsKey(gh))// 使用 散列码 查找
            System.out.println(map.get(gh));
        else System.out.println("Key not found: " + gh);
    }

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        detectSpring(Groundhog.class);
    }
}
/*
map = {Groundhog #4=Six more weeks of Winter!, Groundhog #5=Early Spring!, Groundhog #0=Six more weeks of Winter!, Groundhog #2=Early Spring!, Groundhog #6=Early Spring!, Groundhog #9=Six more weeks of Winter!, Groundhog #3=Early Spring!, Groundhog #7=Early Spring!, Groundhog #8=Six more weeks of Winter!, Groundhog #1=Six more weeks of Winter!}
Looking up prediction for Groundhog #3
Key not found: Groundhog #3
 */
Groundhog自动地继承自基类Object,
所以这里使用Object的hashCode0方法生成散列码,
而它默认是使用对象的地址计算散列码。
因此,由Groundhog(3)生成的第一个实例的散列码与由Groundhog(3)生成的第二个实例的散列码是不同的,而我们正是使用后者进行查找的。
package containers;

public class Groundhog2 extends Groundhog{

    public Groundhog2(int n) {
        super(n);
    }
    public int hashCode(){return number;}
    public boolean equals(Object o){
        return o instanceof Groundhog2 && (number == ((Groundhog2)o).number);
    }
}

package containers;

import java.lang.reflect.InvocationTargetException;

public class SpringDetector2 {
    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        SpringDetector.detectSpring(Groundhog2.class);
    }
}
/*
map = {Groundhog #0=Six more weeks of Winter!, Groundhog #1=Six more weeks of Winter!, Groundhog #2=Early Spring!, Groundhog #3=Early Spring!, Groundhog #4=Six more weeks of Winter!, Groundhog #5=Early Spring!, Groundhog #6=Early Spring!, Groundhog #7=Early Spring!, Groundhog #8=Six more weeks of Winter!, Groundhog #9=Six more weeks of Winter!}
Looking up prediction for Groundhog #3
Early Spring!
 */

9.1 理解 hashCode

9.2 为速度而散列

10 选择接口的不同实现

四种容器

  1. Map
  2. List
  • ArrayList 数组 速度快
  • LinkedList 双向链表 插入和删除
  1. Set
  • TreeSet 基于TreeMap,生成总在排序状态的set
  • HashSet 最常用 查询速度最快
  • LinkedHashSet 保持元素的插入次序
  1. Queue 21章并发 只在 接受和生成数据方式有差别

Hashtable、Vector和Stack遗留类,目的是支持老程序,不要在新程序中使用。

10.1 性能测试框架

模版方法设计模式

package containers;
// Framework for performing timed tests of containers.

public abstract class Test<C> {
  String name;
  public Test(String name){this.name = name;}//测试名称
  // Override this method for different tests.
  // Returns actual number of repetitions of test.
  abstract int test(C container,TestParam tp);
  //待测试容器:泛型参数 C ,
  // messenger or data transfer object:测试参数   size 容器中元素数量,loops,测试迭代次数
}
package containers;

public class TestParam {
  public final int size;// 容器中元素数量
  public final int loops;// 控制迭代的次数
  public TestParam(int size,int loops){
      this.size = size;
      this.loops = loops;
  }
  // Create an array of TestParam from a varargs sequence: 可变参数列表
  public static TestParam[] array(int... values){
      int size = values.length/2;
      TestParam[] result = new TestParam[size];
      int n = 0;
      for (int i = 0; i < size;i++)
          result[i] = new TestParam(values[n++],values[n++]);
      return result;
  }

  // Convert a String array to a TestParam array: 相同类型类别,存储于string,可解析命令行参数
  public static TestParam[] array(String[] values){
      int[] vals = new int[values.length];
      for (int i = 0; i < vals.length;i++)
          vals[i] = Integer.decode(values[i]);
      return array(vals);
  }
}

package containers;

import java.util.List;

public class Tester<C> {
  public static int fieldWidth = 8;
  public static TestParam[] defaultParams = TestParam.array(10,5000,100,5000,1000,5000,10000,500);

  protected C initialize(int size){return container;}
  protected C container;

  private String headline = "";
  private List<Test<C>> tests;
  private static String stringField(){
      return "%" + fieldWidth + "s";
  }
  private static String numberField(){
      return "%" + fieldWidth + "d";
  }

  private static int sizeWidth = 5;
  private static String sizeField = "%" + sizeWidth + "s";

  private TestParam[] paramList = defaultParams;

  public Tester(C container,List<Test<C>> tests){
      this.container = container;
      this.tests = tests;
      if (container != null)
          headline = container.getClass().getSimpleName();
  }
  public Tester(C container,List<Test<C>> tests,TestParam[] paramList){
      this(container,tests);
      this.paramList = paramList;
  }

  public void setHeadline(String newHeadline){
      headline = newHeadline;
  }
  // Generic methods for convenience:
  public static <C> void run(C cntnr,List<Test<C>> tests){
      new Tester<C>(cntnr,tests).timedTest();
  }

  public static <C> void run(C cntnr,List<Test<C>> tests,TestParam[] paramList){
      new Tester<C>(cntnr,tests,paramList).timedTest();
  }

  private void displayHeader(){
      // calculate width and pad with '-'   打印   --- 类名(Container不为空时)或 设置的headline ---
      int width = fieldWidth * tests.size() + sizeWidth;
      int dashLength = width - headline.length() -1;
      StringBuilder head = new StringBuilder(width);
      for (int i = 0; i< dashLength/2;i++)
          head.append('-');
      head.append(' ');
      head.append(headline);
      head.append(' ');
      for (int i = 0; i < dashLength/2; i++)
          head.append('-');
      System.out.println(head);
      // Print column headers 打印表头
      System.out.format(sizeField,"size");
      for (Test test: tests)
          System.out.format(stringField(),test.name);
      System.out.println();
  }
  // Run the tests for this container
  public void timedTest(){
      displayHeader(); //打印测试结果 表头
      for (TestParam param: paramList){
          System.out.format(sizeField,param.size); // 打印测试元素的数量
          for (Test<C> test: tests){
              C kontainer = initialize(param.size); //容器 允许被 重写
              long start = System.nanoTime();
              //Call the overriden method
              int reps = test.test(kontainer,param); // 返回 测试执行的操作 数量
              long duration = System.nanoTime() - start;
              long timePerRep = duration / reps; //单位 纳秒
              System.out.format(numberField(),timePerRep); //打印 该测试 数量时,不同测试用例的测试结果
          }
          System.out.println();//换行,下一组测试数量的测试结果
      }
  }
}

package containers;

import arrays.CountingGenerator;
import arrays.Generated;

import java.util.*;

public class ListPerformance {
  static Random rand = new Random();
  static int reps = 1000;
  static List<Test<List<Integer>>> tests = new ArrayList<>();
  static List<Test<LinkedList<Integer>>> qTests = new ArrayList<>();

  static {
      tests.add(new Test<List<Integer>>("add") {
          @Override
          int test(List<Integer> list, TestParam tp) {
              int loops = tp.loops;
              int listSize = tp.size;
              for (int i = 0; i < loops; i++) {
                  list.clear();
                  for (int j = 0; j < listSize; j++)
                      list.add(j);
              }
              return loops * listSize;
          }

      });

      tests.add(new Test<List<Integer>>("get") {
          @Override
          int test(List<Integer> list, TestParam tp) {
              int loops = tp.loops;
              int listSize = tp.size;
              for (int i = 0; i < loops; i++)
                  list.get(rand.nextInt(listSize)); //随机数
              return loops;
          }
      });
      tests.add(new Test<List<Integer>>("set") {
          @Override
          int test(List<Integer> list, TestParam tp) {
              int loops = tp.loops;
              int listSize = tp.size;
              for (int i = 0; i < loops; i++)
                  list.set(rand.nextInt(listSize), 47);//随机数
              return loops;
          }
      });

      tests.add(new Test<List<Integer>>("iteradd") {
          @Override
          int test(List<Integer> list, TestParam tp) {
              int LOOPS = 1000000;
              int half = list.size() / 2;
              ListIterator<Integer> it = list.listIterator(half);
              for (int i = 0; i < LOOPS; i++)
                  it.add(47);
              return LOOPS;
          }
      });

      tests.add(new Test<List<Integer>>("insert") {
          @Override
          int test(List<Integer> list, TestParam tp) {
              int loops = tp.loops;
              for (int i = 0; i < loops; i++)
                  list.add(5, 47); // Minimize random-access cost 最小化随机存取的成本
              return loops;
          }
      });
      tests.add(new Test<List<Integer>>("remove") {
          @Override
          int test(List<Integer> list, TestParam tp) {
              int loops = tp.loops;
              int size = tp.size;
              for (int i = 0; i < loops; i++) {
                  list.clear();
                  list.addAll(new CountingIntegerList(size));
                  while (list.size() > 5)
                      list.remove(5);// Minimize random-access cost 最小化随机存取的成本
              }
              return loops * size;
          }
      });

      // Tests for queue behavior:
      qTests.add(new Test<LinkedList<Integer>>("addFirst") {
          int test(LinkedList<Integer> list, TestParam tp) {
              int loops = tp.loops;
              int size = tp.size;
              for (int i = 0; i < loops; i++) {
                  list.clear();
                  for (int j = 0; j < size; j++)
                      list.addFirst(47);
              }
              return loops * size;
          }
      });
      qTests.add(new Test<LinkedList<Integer>>("addLast") {
          int test(LinkedList<Integer> list, TestParam tp) {
              int loops = tp.loops;
              int size = tp.size;
              for (int i = 0; i < loops; i++) {
                  list.clear();
                  for (int j = 0; j < size; j++)
                      list.addLast(47);
              }
              return loops * size;
          }
      });
      qTests.add(
              new Test<LinkedList<Integer>>("rmFirst") {
                  int test(LinkedList<Integer> list, TestParam tp) {
                      int loops = tp.loops;
                      int size = tp.size;
                      for (int i = 0; i < loops; i++) {
                          list.clear();
                          list.addAll(new CountingIntegerList(size));
                          while (list.size() > 0)
                              list.removeFirst();
                      }
                      return loops * size;
                  }
              });
      qTests.add(new Test<LinkedList<Integer>>("rmLast") {
          int test(LinkedList<Integer> list, TestParam tp) {
              int loops = tp.loops;
              int size = tp.size;
              for (int i = 0; i < loops; i++) {
                  list.clear();
                  list.addAll(new CountingIntegerList(size));
                  while (list.size() > 0)
                      list.removeLast();
              }
              return loops * size;
          }
      });
  }



  static class ListTester extends Tester<List<Integer>> { // 嵌套类

      public ListTester(List<Integer> container, List<Test<List<Integer>>> tests) {
          super(container, tests);
      }

      // Fill to the appropriate size before each test: add 测试前,需要清除 容器,并重写填充
      @Override
      protected List<Integer> initialize(int size) {
          container.clear();
          container.addAll(new CountingIntegerList(size));
          return container;
      }

      public static void run(List<Integer> list, List<Test<List<Integer>>> tests) {
          new ListTester(list, tests).timedTest();
      }

  }

  public static void main(String[] args) {
      if (args.length > 0)
          Tester.defaultParams = TestParam.array(args);
      // Can only do these two tests on an array: 数组只有 get set,不能有插入或移除
      Tester<List<Integer>> arrayTest = new Tester<List<Integer>>(null, tests.subList(1, 3)) {//匿名内部类 创建特殊的test对象
          // This will be called before each test. It
          // produces a non-resizeable array-backed list:
          @Override
          protected List<Integer> initialize(int size) {
              Integer[] ia = Generated.array(Integer.class, new CountingGenerator.Integer(), size);
              return Arrays.asList(ia);
          }
      };
      arrayTest.setHeadline("Array as List");
      arrayTest.timedTest();
      Tester.defaultParams = TestParam.array(10, 5000, 100, 5000, 1000, 1000, 10000, 200);
      if (args.length > 0)
          Tester.defaultParams = TestParam.array(args);
      ListTester.run(new ArrayList<>(), tests);
      ListTester.run(new LinkedList<>(), tests);
      ListTester.run(new Vector<>(), tests);
      Tester.fieldWidth = 12;
      Tester<LinkedList<Integer>> qTest = new Tester<LinkedList<Integer>>(new LinkedList<Integer>(), qTests);
      qTest.setHeadline("Queue tests");
      qTest.timedTest();
  }
}
/*
--- Array as List ---
size     get     set
 10     323     139
100      39      51
1000      35     107
10000      54      70
--------------------- ArrayList ---------------------
size     add     get     set iteradd  insert  remove
 10      47     102     142      27     229     123
100      14      40      60      15     208      25
1000      20      40      48      38     184      48
10000       9      64      62     293     788     377
--------------------- LinkedList ---------------------
size     add     get     set iteradd  insert  remove
 10      50     196     157      33     200      73
100      10      78      83      11      43      20
1000       8     383     394       5      36      23
10000      16    3582    3553       5      43      13
----------------------- Vector -----------------------
size     add     get     set iteradd  insert  remove
 10      56      94      88      38     187      59
100      19      49      60      35     176      42
1000      19      77      59      57     124      71
10000      19     134      62     310     766     368
-------------------- Queue tests --------------------
size    addFirst     addLast     rmFirst      rmLast
 10          46          43          56          59
100          19          19          22          21
1000          18          18          21           9
10000           6           7          10           9
*/

CopyOnWriteArrayList是List特殊实现,用于并发编程。21章。

10.2对List的选择

10.3 微基准测试的危险

微基准测试 microbenchmarks 需要 测试窄化,测试时间足够长,以产生有意义到数据

根据计算机和所使用jvm不同,测试结果也不同。

剖析器 profiler:性能分析工作做的更好,java提供或第三方工具

举例:实验的误导,看起来永远都不会生成0.0或1.0,

但已证明0.0 是包含在输出中的

因此需要分析试验,并理解它们的局限性。

Math.random [0,1)

参数lower 或 upper
需要手动中断
   package containers;
import static net.mindview.util.Print.*;

public class RandomBounds {
    static void usage() {
        print("Usage:");
        print("\tRandomBounds lower");
        print("\tRandomBounds upper");
        System.exit(1);
    }
    public static void main(String[] args) {
        if(args.length != 1) usage();
        if(args[0].equals("lower")) {
            while(Math.random() != 0.0)
                ; // Keep trying
            print("Produced 0.0!");
        }
        else if(args[0].equals("upper")) {
            while(Math.random() != 1.0)
                ; // Keep trying
            print("Produced 1.0!");
        } else
            usage(); }
}

10.4 对Set的选择

TreeSet,HashSet,LinkedHashSet

  package containers;

import java.util.*;

public class SetPerformance {
    static List<Test<Set<Integer>>> tests =
            new ArrayList<>();

    static {
        tests.add(new Test<Set<Integer>>("add") {
            @Override
            int test(Set<Integer> set, TestParam tp) {
                for (int i = 0; i < tp.loops; i++) {
                    set.clear();
                    for (int j = 0; j < tp.size; j++)
                        set.add(j);
                }
                return tp.loops * tp.size;
            }
        });

        tests.add(new Test<Set<Integer>>("contains") {
            @Override
            int test(Set<Integer> set, TestParam tp) {
                for (int i = 0; i < tp.loops; i++) {
                    for (int j = 0; j < tp.size * 2; j++)
                        set.contains(j);
                }
                return tp.loops * tp.size;
            }
        });
        tests.add(new Test<Set<Integer>>("iterate") {
            @Override
            int test(Set<Integer> set, TestParam tp) {
                int loops = tp.loops *10;
                for (int i = 0; i < loops; i++) {
                    Iterator<Integer> it = set.iterator();
                    while (it.hasNext())
                        it.next();
                }
                return loops*set.size();
            }
        });
    }

    public static void main(String[] args) {
        Tester.fieldWidth = 10;
        Tester.run(new TreeSet<Integer>(),tests);
        Tester.run(new HashSet<Integer>(),tests);
        Tester.run(new LinkedHashSet<Integer>(),tests);
    }
}
/*
------------- TreeSet -------------
 size       add  contains   iterate
   10       250        97        21
  100        54        45         5
 1000        52        83         4
10000        68       100         5
------------- HashSet -------------
 size       add  contains   iterate
   10        79       129        36
  100         9         6         5
 1000        11         8         4
10000        10         9         4
---------- LinkedHashSet ----------
 size       add  contains   iterate
   10       136        59        11
  100        20        15         4
 1000        19        18         4
10000        19        18         4
 */

HashSet 性能基本上总比TreeSet好

TreeSet 存在的唯一原因 是它可以维持元素对排序状态,当需要排序好的Set时候,才使用TreeSet,其内部结构支持排序,迭代比HashSet快

LinkedHashSet 比 HashSet 代价高,需要维护链表。

10.5 对Map的选择

package containers;

import java.util.*;

public class MapPerformance {
    static List<Test<Map<Integer, Integer>>> tests = new ArrayList<>();

    static {
        tests.add(new Test<Map<Integer, Integer>>("put") {
            @Override
            int test(Map<Integer, Integer> map, TestParam tp) {
                int loops = tp.loops;
                int size = tp.size;
                for (int i = 0; i < loops; i++) {
                    map.clear();
                    for (int j = 0; j < size; j++)
                        map.put(i, j);
                }
                return loops * size;
            }
        });
        tests.add(new Test<Map<Integer,Integer>>("get") {
            int test(Map<Integer,Integer> map, TestParam tp) {
                int loops = tp.loops;
                int span = tp.size * 2;
                for(int i = 0; i < loops; i++)
                    for(int j = 0; j < span; j++)
                        map.get(j);
                return loops * span;
            }
        });
        tests.add(new Test<Map<Integer,Integer>>("iterate") {
            int test(Map<Integer,Integer> map, TestParam tp) {
                int loops = tp.loops * 10;
                for(int i = 0; i < loops; i ++) {
                    Iterator it = map.entrySet().iterator();
                    while(it.hasNext())
                        it.next(); }
                return loops * map.size();
            }
        });
    }

    public static void main(String[] args) {
        if(args.length > 0)
            Tester.defaultParams = TestParam.array(args);
        Tester.fieldWidth = 20;
        Tester.run(new TreeMap<Integer,Integer>(), tests);
        Tester.run(new HashMap<Integer,Integer>(), tests);
        Tester.run(new LinkedHashMap<Integer,Integer>(),tests);
        Tester.run(
                new IdentityHashMap<Integer,Integer>(), tests);
        Tester.run(new WeakHashMap<Integer,Integer>(), tests);
        Tester.run(new Hashtable<Integer,Integer>(), tests);
    }
}

---------------------------- TreeMap ----------------------------
 size                 put                 get             iterate
   10                  84                  36                 109
  100                  19                   7                  35
 1000                   9                   4                  40
10000                  10                   5                   1
---------------------------- HashMap ----------------------------
 size                 put                 get             iterate
   10                  81                  74                 186
  100                   8                   2                  26
 1000                  18                   5                  22
10000                  10                   4                  23
------------------------- LinkedHashMap -------------------------
 size                 put                 get             iterate
   10                 258                  29                  65
  100                  13                   7                  13
 1000                  19                  16                  23
10000                  18                   9                 100
------------------------ IdentityHashMap ------------------------
 size                 put                 get             iterate
   10                  96                  25                  18
  100                  62                  24                  10
 1000                  60                  56                  17
10000                  50                  63                  13
-------------------------- WeakHashMap --------------------------
 size                 put                 get             iterate
   10                  74                  22                 142
  100                   9                   5                  24
 1000                   9                   5                  24
10000                  10                   7                  24
--------------------------- Hashtable ---------------------------
 size                 put                 get             iterate
   10                  38                  18                  99
  100                  12                   8                  21
 1000                  12                   9                  23
10000                  12                  22                  21

除了IdentityHashMap,MAP插入操作随着MAP尺寸变大明显变慢(这个不明显,不确定是否是SDK优化),但查找的代价比插入小。

Hashtable 与HashMap 相当,HashMap 是用来替换Hashtable的,使用相同对底层存储和查找机制。

TreeMap 比 HashMap 慢。与TreeSet一样,是创建有序列表的方式,可以使用keySet方法获取Set视图。然后可以用toArray产生键构成对数组。Arrays.binary.Search快速查找。优先HashMap,需要保持有序时,使用TreeMap

LinkedHashMap 插入慢,除了维护散列数据结构,还维护链表,使得迭代速度快

IdentityHashMap 具有完全不同对性能,使用== 而不是equals比较元素。

HashMap的性能因子
容量 表中的桶位数
初始容量
尺寸
负载因子 尺寸/容量

11 实用方法

package containers;

import java.util.*;

public class Utilities {
    static List<String> list = Arrays.asList("one Two three Four five six one".split(" "));

    public static void main(String[] args) {
        System.out.println(list);
        System.out.println("'list' disjoint (Four)?: " + Collections.disjoint(list,Collections.singletonList("Four") ));
        System.out.println("max: " + Collections.max(list));
        System.out.println("min: " + Collections.min(list));
        System.out.println("max w/ comparator: " + Collections.max(list,String.CASE_INSENSITIVE_ORDER));
        System.out.println("mix w/ comparator: " + Collections.min(list,String.CASE_INSENSITIVE_ORDER));
        List<String> sublist = Arrays.asList("Four five six".split(" "));
        System.out.println("indexofSublist: " + Collections.indexOfSubList(list,sublist));
        System.out.println("lastIndexOfSublist: " + Collections.lastIndexOfSubList(list,sublist));
        Collections.replaceAll(list,"one","Yo");
        System.out.println("replaceAll: " + list);
        Collections.reverse(list);
        System.out.println("reverse: " + list);
        Collections.rotate(list,3);
        System.out.println("rotate: " + list);
        List<String> source = Arrays.asList("in the matrix".split(" "));
        Collections.copy(list,source);
        System.out.println("copy: " + list);
        Collections.swap(list,0,list.size()-1);
        System.out.println("swap: " + list);
        Collections.shuffle(list,new Random(47));
        System.out.println("shuffled: " + list);
        Collections.fill(list,"pop");
        System.out.println("fill: " + list);
        System.out.println("frequency of ‘pop’: " +
                Collections.frequency(list, "pop"));
        List<String> dups = Collections.nCopies(3, "snap");
        System.out.println("dups: " + dups);
        System.out.println("‘list’ disjoint ‘dups’?: " +
                Collections.disjoint(list, dups));
        // Getting an old-style Enumeration:
        Enumeration<String> e = Collections.enumeration(dups);
        Vector<String> v = new Vector<String>();
        while(e.hasMoreElements())
            v.addElement(e.nextElement());
        // Converting an old-style Vector
        // to a List via an Enumeration:
        ArrayList<String> arrayList =
                Collections.list(v.elements());
        System.out.println("arrayList: " + arrayList);
    }
}
/*
[one, Two, three, Four, five, six, one]
'list' disjoint (Four)?: false
max: three
min: Four
max w/ comparator: Two
mix w/ comparator: five
indexofSublist: 3
lastIndexOfSublist: 3
replaceAll: [Yo, Two, three, Four, five, six, Yo]
reverse: [Yo, six, five, Four, three, Two, Yo]
rotate: [three, Two, Yo, Yo, six, five, Four]
copy: [in, the, matrix, Yo, six, five, Four]
swap: [Four, the, matrix, Yo, six, five, in]
shuffled: [six, matrix, the, Four, Yo, five, in]
fill: [pop, pop, pop, pop, pop, pop, pop]
frequency of ‘pop’: 7
dups: [snap, snap, snap]
‘list’ disjoint ‘dups’?: true
arrayList: [snap, snap, snap]
 */

11.1 List的排序和查询

package containers;

import java.util.*;

public class ListSortSearch {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(Utilities.list);
        list.addAll(Utilities.list);
        System.out.println(list);
        Collections.shuffle(list, new Random(47));
        System.out.println("Shuffled: " + list);
        ListIterator<String> it = list.listIterator(10);
        while (it.hasNext()) {
            it.next();
            it.remove();
        }
        System.out.println("Trimmed: " + list);
        Collections.sort(list);
        System.out.println("Sorted: " + list);
        String key = list.get(7);
        int index = Collections.binarySearch(list, key);
        System.out.println("Location of " + key + " is " + index + " . list.get(" + index + ") = " + list.get(index));
        Collections.sort(list,String.CASE_INSENSITIVE_ORDER);
        System.out.println("Case_insensitive sorted: " + list);
        key = list.get(7);
        index = Collections.binarySearch(list,key,String.CASE_INSENSITIVE_ORDER);
        System.out.println("Location of " + key + " is " + index + " . list.get(" + index + ") = " + list.get(index));

    }
}
/*
[one, Two, three, Four, five, six, one, one, Two, three, Four, five, six, one]
Shuffled: [Four, five, one, one, Two, six, six, three, three, five, Four, Two, one, one]
Trimmed: [Four, five, one, one, Two, six, six, three, three, five]
Sorted: [Four, Two, five, five, one, one, six, six, three, three]
Location of six is 7 . list.get(7) = six
Case_insensitive sorted: [five, five, Four, one, one, six, six, three, three, Two]
Location of three is 7 . list.get(7) = three
 */

11.2 设定Collection或Map为不可修改

package containers;

import java.util.*;

public class ReadOnly {
    static Collection<String> data = new ArrayList<String>(Countries.names(6));

    public static void main(String[] args) {
        Collection<String> c = Collections.unmodifiableCollection(new ArrayList<>(data));
        System.out.println(c);
//        c.add("one");//Immutable object is modified

        List<String> a = Collections.unmodifiableList(new ArrayList<>(data));
        ListIterator<String> it = a.listIterator();
        System.out.println(it.next());
//        it.add("one"); //UnsupportedOperationException

        Set<String> s = Collections.unmodifiableSet(new HashSet<String>(data));
        System.out.println(s);
//        s.add("one");//Immutable object is modified

        //for a SortedSet
        Set<String> ss = Collections.unmodifiableSortedSet(new TreeSet<>(data));
        System.out.println(ss);

        Map<String, String> m = Collections.unmodifiableMap(new HashMap<>(Countries.capitals(6)));
        System.out.println(m);
//        m.put("kdd", "ddd");//Immutable object is modified

        // For a SortedMap:
        Map<String, String> sm =
                Collections.unmodifiableSortedMap(
                        new TreeMap<String, String>(Countries.capitals(6)));


    }
}
/*
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI]
ALGERIA
[BENIN, BOTSWANA, ANGOLA, BURKINA FASO, ALGERIA, BURUNDI]
[ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI]
{BENIN=Porto-Novo, BOTSWANA=Gaberone, ANGOLA=Luanda, BURKINA FASO=Ouagadougou, ALGERIA=Algiers, BURUNDI=Bujumbura}
 */

11.3 Collection或Map的同步控制

public class Synchronization {
    public static void main(String[] args) {
        Collection<String> c =
                Collections.synchronizedCollection(
                        new ArrayList<String>());
        List<String> list = Collections.synchronizedList(new ArrayList<>());
        Set<String> set = Collections.synchronizedSet(new HashSet<>());
        Set<String> ss = Collections.synchronizedSortedSet(new TreeSet<>());
        Map<String,String> m = Collections.synchronizedMap(new HashMap<>());
        Map<String,String> sm = Collections.synchronizedSortedMap(new TreeMap<>());
    }
}

快速报错
fail-fast

package containers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;

public class FailFast {
    public static void main(String[] args) {
        Collection<String> c = new ArrayList<String>();
        Iterator<String> it = c.iterator();
        c.add("An object");
        try {
            String s = it.next();
        } catch(ConcurrentModificationException e) {
            System.out.println(e);
        }
    }
}
/*
java.util.ConcurrentModificationException

ConcurrentHashMap, CopyOnWriteArrayList, and CopyOnWriteArraySet 
 */

12 持有引用

除了原始数据类型的变量,其他所有都是所谓的引用类型,指向各种不同的对象。

不同的引用类型,对象不同的可达性状态,对垃圾收集的影响。

强引用:普通对象引用。对象还活着,垃圾收集器不会碰这种对象。如果对象没有其他引用,只要超过引用作用域或显式的强引用赋值为null,可以被垃圾收集,具体时机还要看垃圾收集策略。

软引用SoftReference:相对强引用弱化一些,可以豁免一些垃圾收集,JVM认为内存不足时,才会去试图回收软引用指向的对象。在抛出OutofMemory之前,清理软引用指向的对象。通常用来实现内存敏感的缓存。

弱引用WeakReference:并不能使对象豁免垃圾收集,维护一种非强制性的映射关 系,如果试图获取时对象还在,就使用它,否则重现实例化。

虚引用,不能通过它访问对象,确保对象被finalize后,做某些事情的机制。通常用来做所谓的 Post-Mortem 清理机制,也有利用虚引用监控对象的创建和销毁。

java.lang.ref类库包含了一组类,这些类为垃圾回收提供了更大的灵活性。当存在可能会耗尽内存的大对象时,这些类显得特别有用。有三个继承自抽象类Reference的类:SoftReference、WeakReference和PhantomReference。当垃圾回收器正在考察的对象只能通过某个Reference对象才可获得时,上诉这些不同的派生类为垃圾回收器提供了不同级别的间接性指示。

对象是可获得的(reachable),是指此对象可在程序中的某处找到,这意味着在栈中有一个普通引用,它指向此对象。如果一个对象是可获得的,垃圾回收器就不能释放它,因为它仍然为程序所用。如果一个对象不是可获得的,那程序将无法使用它,所以将其回收是安全的。

SoftReference、WeakReference和PhantomReference由强到弱排列,对应不同级别“可获得性”。

SoftReference用以实现内存敏感的高速缓存。
WeakReference是为实现规范映射而设计,它不妨碍垃圾回收器回收映射的键或值。规范映射中对象的实例可以在程序的多出被同时使用,以节省存储空间。
PhantomReference用以调度回收前的清理工作,它比Java终止机制更灵活。

package containers;

import java.lang.ref.*;
import java.util.LinkedList;

class VeryBig{
    private static final int SIZE = 10000;
    private long[] la = new long[SIZE];
    private String ident;
    public VeryBig(String id){ident = id;}
    public String toString(){return ident;}
    protected void finalize(){
        System.out.println("Finalizing " + ident);
    }
}
public class References {
    private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<>();
    public static void checkQueue(){
        Reference<? extends VeryBig> inq = rq.poll();
        // 可以调用ReferenceQueue的poll()方法来检查是否有它所 关心的对象被回收。
        // 如果队列为空,将返回一个null,否则该方法返回队列中前面的一个Reference对象。
        if (inq != null)
            System.out.println("In queue: " + inq.get());
    }

    public static void main(String[] args) {
        int size = 10;
        // 或者通过命令行输入size
        if (args.length > 0)
            size = new Integer(args[0]);

        LinkedList<SoftReference<VeryBig>> sa = new LinkedList<>();
        for (int i = 0; i< size; i++){
            sa.add(new SoftReference<>(new VeryBig("soft " +i),rq));
            System.out.println("Just created: " + sa.getLast());
            checkQueue();
        }

        LinkedList<WeakReference<VeryBig>> wa =
                new LinkedList<WeakReference<VeryBig>>();
        for(int i = 0; i < size; i++) {
            wa.add(new WeakReference<VeryBig>(
                    new VeryBig("Weak " + i), rq));
            System.out.println("Just created: " + wa.getLast());
            checkQueue();
        }
        SoftReference<VeryBig> s =
                new SoftReference<VeryBig>(new VeryBig("Soft"));
        WeakReference<VeryBig> w =
                new WeakReference<VeryBig>(new VeryBig("Weak"));
        System.gc();

        LinkedList<PhantomReference<VeryBig>> pa =
                new LinkedList<PhantomReference<VeryBig>>();
        for(int i = 0; i < size; i++) {
            pa.add(new PhantomReference<VeryBig>(
                    new VeryBig("Phantom " + i), rq));
            System.out.println("Just created: " + pa.getLast());
            checkQueue();
        }
    }
}
/*
Just created: java.lang.ref.SoftReference@5e481248
Just created: java.lang.ref.SoftReference@66d3c617
Just created: java.lang.ref.SoftReference@63947c6b
Just created: java.lang.ref.SoftReference@2b193f2d
Just created: java.lang.ref.SoftReference@355da254
Just created: java.lang.ref.SoftReference@4dc63996
Just created: java.lang.ref.SoftReference@d716361
Just created: java.lang.ref.SoftReference@6ff3c5b5
Just created: java.lang.ref.SoftReference@3764951d
Just created: java.lang.ref.SoftReference@4b1210ee
Just created: java.lang.ref.WeakReference@4d7e1886
Just created: java.lang.ref.WeakReference@3cd1a2f1
Just created: java.lang.ref.WeakReference@2f0e140b
Just created: java.lang.ref.WeakReference@7440e464
Just created: java.lang.ref.WeakReference@49476842
Just created: java.lang.ref.WeakReference@78308db1
Just created: java.lang.ref.WeakReference@27c170f0
Just created: java.lang.ref.WeakReference@5451c3a8
Just created: java.lang.ref.WeakReference@2626b418
Just created: java.lang.ref.WeakReference@5a07e868
Just created: java.lang.ref.PhantomReference@76ed5528
Finalizing Weak 4
In queue: null
Just created: java.lang.ref.PhantomReference@2c7b84de
In queue: null
Finalizing Weak
Just created: java.lang.ref.PhantomReference@3fee733d
Finalizing Weak 9
In queue: null
Finalizing Weak 8
Just created: java.lang.ref.PhantomReference@5acf9800
Finalizing Weak 7
In queue: null
Finalizing Weak 6
Just created: java.lang.ref.PhantomReference@4617c264
In queue: null
Finalizing Weak 5
Finalizing Weak 3
Just created: java.lang.ref.PhantomReference@36baf30c
In queue: null
Finalizing Weak 2
Just created: java.lang.ref.PhantomReference@7a81197d
In queue: null
Finalizing Weak 1
Just created: java.lang.ref.PhantomReference@5ca881b5
In queue: null
Finalizing Weak 0
Just created: java.lang.ref.PhantomReference@24d46ca6
In queue: null
Just created: java.lang.ref.PhantomReference@4517d9a3
In queue: null
 */

 posted on 2019-12-04 17:12  erinchen  阅读(226)  评论(0编辑  收藏  举报