当前位置: 首页 > news >正文

个人注册公司网站空间常德建设网站

个人注册公司网站空间,常德建设网站,餐饮公司 网站建设,网站的要素是什么注意#xff1a; 17章接着 11章继续分析 java容器#xff0c; think-in-java(11) 【17.1】完整的容器分类方法 【容器分类网络解说】 1#xff09;接口#xff1a;虚线框#xff0c;没有实线入边#xff08;没有实体类继承关系#xff0c;只有接口继承关系#xff09…注意 17章接着 11章继续分析 java容器 think-in-java(11) 【17.1】完整的容器分类方法 【容器分类网络解说】 1接口虚线框没有实线入边没有实体类继承关系只有接口继承关系 2抽象类虚线框有实现入边有实体类继承关系SortedSet 除外SortedSet 明显是一个接口 TreeSet 实现了 NavigableSet 接口而 NavigableSet 接口继承了 SortedSet  接口来自java 8 版本 3实体类其他的都是继承关系 4常用实体类 加粗实线框 5Collections 和 Arrays 是工具类 java 5 添加了新特性 1Queue接口队列可以通过 LinkedList来实现了当然包括 Stack栈数据结构机器实现 PriorityQueue 和 BlockingQueue阻塞队列21章 java 多线程编程介绍 2ConcurrentMap 接口 和 实现类 CurrentHashMap也在21章 3CopyOnWriteArrayList 和 CopyOnWriteArraySet 也是多线程的内容 4EnumSet 和 EnumMap为使用 enum 而设计的 Set 和 Map的特殊实现 5Collections类中添加了多个 便利的工具方法 【17.2】填充容器 1用单个对象引用来填充 Collection通过 Collections.nCopies() 方法 添加 而通过 Collections.fill() 来替换添加 class StringAddress {private String s;public StringAddress(String s) {this.s s;}public String toString() {return super.toString() s;} }public class FillingLists {public static void main(String[] args) {/* 构建4个StringAddress对象并封装到List 操作的都是同一个对象 */ListStringAddress list new ArrayListStringAddress(Collections.nCopies(4, new StringAddress(Hello)));System.out.println(list);/* 把 新对象StringAddress引用 填充到list中 操作的都是同一个对象 *//* Collections.fill() 方法只能替换 list中已经存在的元素不能添加新元素 */Collections.fill(list, new StringAddress(World!));System.out.println(list);} } // 打印结果List使用的都是同一个对象引用 [chapter17.StringAddress15db9742 Hello, chapter17.StringAddress15db9742 Hello, chapter17.StringAddress15db9742 Hello, chapter17.StringAddress15db9742 Hello] [chapter17.StringAddress6d06d69c World!, chapter17.StringAddress6d06d69c World!, chapter17.StringAddress6d06d69c World!, chapter17.StringAddress6d06d69c World!]【17.2.1】一种 Generator 解决方案 1所有Collection的子容器都有接受另一个 Collection 对象的构造器用所接受的 Collection对象中的元素来填充新容器 【荔枝】通过适配器模式模拟 将 Collection容器对象作为输入参数传入 另一个 Collection的构造方法 class Government implements GeneratorString {String[] foundation (strange women lying in ponds distributing swords is no basis for a system of government).split( );private int index;public String next() {return foundation[index];} }public class CollectionDataTest {public static void main(String[] args) {/* ArrayList容器作为参数传入 LinkedHashSet 构造器这个适配器代码很经典的 */SetString set new LinkedHashSetString(new CollectionDataString(new Government(), 15));// Using the convenience method:set.addAll(CollectionData.list(new Government(), 15));System.out.println(set);} } /* public class CollectionDataT extends ArrayListT {// Generator类public CollectionData(GeneratorT gen, int quantity) {for (int i 0; i quantity; i)add(gen.next());}// A generic convenience method:public static T CollectionDataT list(GeneratorT gen, int quantity) {return new CollectionDataT(gen, quantity);} } // 打印结果 [strange, women, lying, in, ponds, distributing, swords, is, no, basis, for, a, system, of, government]public interface GeneratorT { T next(); } ///:~ 【元素的输出顺序与 插入顺序相同】因为 LinkedHashSet 保持了插入顺序的链表列表 【CollectionData 应用的荔枝】 public class CollectionDataGeneration {public static void main(String[] args) {/* Convenience method */System.out.println(new ArrayListString(CollectionData.list(new RandomGenerator.String(9), 10)));System.out.println(new HashSetInteger(new CollectionDataInteger(new RandomGenerator.Integer(), 10)));} } // 打印结果 [YNzbrnyGc, FOWZnTcQr, GseGZMmJM, RoEsuEcUO, neOEdLsmw, HLGEahKcx, rEqUCBbkI, naMesbtWH, kjUrUkZPg, wsqPzDyCy] [2017, 8037, 871, 7882, 6090, 4779, 299, 573, 4367, 3455] 【17.2.2】Map 生成器 【荔枝】将 Generator适配到 Map的构造器中 // 键值对类 public class PairK, V {public final K key;public final V value;public Pair(K k, V v) {key k;value v;} } public class MapDataK, V extends LinkedHashMapK, V {// A single Pair Generator:public MapData(GeneratorPairK, V gen, int quantity) { // 使用一个 generator 构建 mapfor (int i 0; i quantity; i) {PairK, V p gen.next();put(p.key, p.value);}}// Two separate Generators:public MapData(GeneratorK genK, GeneratorV genV, int quantity) { // 使用两个 generator 构建mapfor (int i 0; i quantity; i) {put(genK.next(), genV.next());}}// A key Generator and a single value:public MapData(GeneratorK genK, V value, int quantity) { // 使用一个 泛型为key的generator但值都相同的方法构建 map。for (int i 0; i quantity; i) {put(genK.next(), value);}}// An Iterable and a value Generator:public MapData(IterableK genK, GeneratorV genV) { // 使用 Iterable 和 一个 generator 构建mapfor (K key : genK) {put(key, genV.next());}}// An Iterable and a single value:public MapData(IterableK genK, V value) { // 使用一个 泛型为 key的Iterable 但值都相同的 方式构建mapfor (K key : genK) {put(key, value);}}// Generic convenience methods:泛型简单方法调用以上的构造方法public static K, V MapDataK, V map(GeneratorPairK, V gen,int quantity) {return new MapDataK, V(gen, quantity);}public static K, V MapDataK, V map(GeneratorK genK,GeneratorV genV, int quantity) {return new MapDataK, V(genK, genV, quantity);}public static K, V MapDataK, V map(GeneratorK genK, V value,int quantity) {return new MapDataK, V(genK, value, quantity);}public static K, V MapDataK, V map(IterableK genK, GeneratorV genV) {return new MapDataK, V(genK, genV);}public static K, V MapDataK, V map(IterableK genK, V value) {return new MapDataK, V(genK, value);} } 【荔枝】调用MapData构建 Map的荔枝 class Letters implements GeneratorPairInteger, String, IterableInteger {private int size 9;private int number 1;private char letter A;public PairInteger, String next() {return new PairInteger, String(number, letter);}public IteratorInteger iterator() {return new IteratorInteger() {public Integer next() {return number;}public boolean hasNext() {return number size;}public void remove() {throw new UnsupportedOperationException();}};} } public class MapDataTest {public static void main(String[] args) {/* 以下构造方式看懂一个即可。非常经典的使用 一个容器 构造另一个容器的方法调用过程非常经典 */// Pair Generator:print(MapData.map(new Letters(), 11)); // Two separate generators:print(MapData.map(new CountingGenerator.Character(), new RandomGenerator.String(3), 8));// A key Generator and a single value:print(MapData.map(new CountingGenerator.Character(), Value, 6));// An Iterable and a value Generator:print(MapData.map(new Letters(), new RandomGenerator.String(3)));// An Iterable and a single value:print(MapData.map(new Letters(), Pop));} } // 打印结果 {1A, 2B, 3C, 4D, 5E, 6F, 7G, 8H, 9I, 10J, 11K} {aYNz, bbrn, cyGc, dFOW, eZnT, fcQr, gGse, hGZM} {aValue, bValue, cValue, dValue, eValue, fValue} {1mJM, 2RoE, 3suE, 4cUO, 5neO, 6EdL, 7smw, 8HLG} {1Pop, 2Pop, 3Pop, 4Pop, 5Pop, 6Pop, 7Pop, 8Pop} 【补充】 可以使用工具来创建 任何用于 Map 或 Collection 的生成数据集然后通过 构造器 或 Map.putAll() 和 Collection.putAll() 来初始化 Map 和Collection 【总结】Collection的一个项存储一个值而map 的一个项存储一个键值对以上是 把 generator 适配到 Collection 和 map 的构造过程的方式非常经典的调用果然厉害 【17.2.3】使用 Abstract 显然 各种容器对应 的 Abstract类 是 继承了 容器基类接口实现基类接口的一部分方法或全部方法然后实体类容器 再来继承 Abstract类这样实体类容器无需实现 容器接口的全部方法。如AbstractCollection AbstractSet AbstractList AbstractMap 等容器抽象类 【荔枝】创建定制的Map 和 Collection  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, Ndjamena },{ 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 DIVOIR (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, Pyongyang },{ 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, Sanaa },// 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, Nukualofa },{ 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 Johns }, { 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 Georges },{ 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(): 实现 entrySet()方法来 应用 AbstractMap 抽象类private static class FlyweightMap extends AbstractMapString, String {// 静态内部类private static class Entry implements Map.EntryString, String { // 静态内部类int index;Entry(int index) {this.index index;}/* 判断 key 是否相等 */public boolean equals(Object o) {return DATA[index][0].equals(o);}public String getKey() {return DATA[index][0];}public String getValue() {return DATA[index][1];}public String setValue(String value) {throw new UnsupportedOperationException();}/* key的 哈希值 */public int hashCode() {return DATA[index][0].hashCode();}}// Use AbstractSet by implementing size() iterator(): 通过实现 size() 和 iterator() 方法来应用 AbstractSet 抽象类static class EntrySet extends AbstractSetMap.EntryString, String {// 静态内部类private int size;EntrySet(int size) {if (size 0)this.size 0;// Cant be any bigger than the array:else if (size DATA.length)this.size DATA.length;elsethis.size size;}public int size() {return size;}private class Iter implements IteratorMap.EntryString, String { // 内部类// Only one Entry object per Iterator:Collection col;private Entry entry new Entry(-1);public boolean hasNext() {return entry.index size - 1;}public Map.EntryString, String next() {entry.index;return entry;}public void remove() {throw new UnsupportedOperationException();}}public IteratorMap.EntryString, String iterator() {return new Iter();}}private static SetMap.EntryString, String entries new EntrySet(DATA.length);public SetMap.EntryString, String entrySet() {return entries;}}// Create a partial map of size countries:static MapString, String select(final int size) {HashMap map null;return new FlyweightMap() { Overridepublic SetMap.EntryString, String entrySet() {return new EntrySet(size);}};}static MapString, String map new FlyweightMap();// 返回 存储首都的 map容器public static MapString, String capitals() {return map; // The entire map}// 返回给定size 的 mappublic static MapString, String capitals(int size) {return select(size); // A partial map}static ListString names new ArrayListString(map.keySet());// 返回所有的 names public static ListString names() {return names;}// 返回给定 size 的 name listpublic static ListString names(int size) {return new ArrayListString(select(size).keySet());}public static void main(String[] args) {print(capitals(10)); print(names(10));print(new HashMapString, String(capitals(3)));print(new LinkedHashMapString, String(capitals(3)));print(new TreeMapString, String(capitals(3)));print(new HashtableString, String(capitals(3)));print(new HashSetString(names(6)));print(new LinkedHashSetString(names(6)));print(new TreeSetString(names(6)));print(new ArrayListString(names(6)));print(new LinkedListString(names(6)));print(capitals().get(BRAZIL));} } // 打印结果 {ALGERIAAlgiers, ANGOLALuanda, BENINPorto-Novo, BOTSWANAGaberone, BURKINA FASOOuagadougou, BURUNDIBujumbura, CAMEROONYaounde, CAPE VERDEPraia, CENTRAL AFRICAN REPUBLICBangui, CHADNdjamena} [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI, CAMEROON, CAPE VERDE, CENTRAL AFRICAN REPUBLIC, CHAD] {BENINPorto-Novo, ANGOLALuanda, ALGERIAAlgiers} {ALGERIAAlgiers, ANGOLALuanda, BENINPorto-Novo} {ALGERIAAlgiers, ANGOLALuanda, BENINPorto-Novo} {ALGERIAAlgiers, ANGOLALuanda, BENINPorto-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 【荔枝的关键之处】 通过继承容器抽象类来创建定制的 Map 和 Collection 有多简单。。为了创建只读的 Map可以继承 AbstractMap 并实现 entrySet() 方法。为了创建只读的 Set 可以继承 AbstractSet 并实现 iterator()  和 size()方法 【定制ArrayList的荔枝】 public class CountingIntegerList extends AbstractListInteger {private int size;public CountingIntegerList(int size) {this.size size 0 ? 0 : size;}public Integer get(int index) {return Integer.valueOf(index);}public int size() {return size;}public static void main(String[] args) {System.out.println(new CountingIntegerList(30));} } /** Output: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,* 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]*/// :~ 【代码解说】为了基于 AbstractList 创建只读的List 必须实现 size() 和 get() 方法 【荔枝】创建定制的Map public class CountingMapData extends AbstractMapInteger, 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) {if (size 0)this.size 0;this.size size;}private static class Entry implements Map.EntryInteger, String {// 静态内部类int index;Entry(int index) {this.index index;}public boolean equals(Object o) {return Integer.valueOf(index).equals(o);}public Integer getKey() {return index;}public String getValue() {return chars[index % chars.length] Integer.toString(index / chars.length);}public String setValue(String value) {throw new UnsupportedOperationException();}public int hashCode() {return Integer.valueOf(index).hashCode();}}public SetMap.EntryInteger, String entrySet() {// LinkedHashSet retains initialization order: // LinkedHashSet 保持了初始化顺序。SetMap.EntryInteger, String entries new LinkedHashSetMap.EntryInteger, String();for (int i 0; i size; i)entries.add(new Entry(i));return entries;}public static void main(String[] args) {/*AbstractMap的toString() 方法调用了 entrySet().iterator() 迭代器*//* iteraotr迭代器 调用了 entry.getKey() 和 entry.getValue() 方法 */System.out.println(new CountingMapData(60));} } /** Output: {0A0, 1B0, 2C0, 3D0, 4E0, 5F0, 6G0, 7H0, 8I0, 9J0, 10K0,* 11L0, 12M0, 13N0, 14O0, 15P0, 16Q0, 17R0, 18S0, 19T0, 20U0, 21V0,* 22W0, 23X0, 24Y0, 25Z0, 26A1, 27B1, 28C1, 29D1, 30E1, 31F1, 32G1,* 33H1, 34I1, 35J1, 36K1, 37L1, 38M1, 39N1, 40O1, 41P1, 42Q1, 43R1,* 44S1, 45T1, 46U1, 47V1, 48W1, 49X1, 50Y1, 51Z1, 52A2, 53B2, 54C2,* 55D2, 56E2, 57F2, 58G2, 59H2}*/// :~ 【17.3】Collection的功能方法 【荔枝】Collection方法列表展示 public class CollectionMethods {public static void main(String[] args) {CollectionString c new ArrayListString();c.addAll(Countries.names(6));c.add(ten);c.add(eleven);print(c , c);/* list 转 数组 */Object[] array c.toArray(); // Make a String array from the List:String[] str c.toArray(new String[0]);/* Collections.max() 和 Collections.min() 方法找出list的最大最小值 */print(Collections.max(c) Collections.max(c));print(Collections.min(c) Collections.min(c));/* addAll(): 把一个容器添加到另一个容器中 */CollectionString c2 new ArrayListString();c2.addAll(Countries.names(6));c.addAll(c2);print(c2.addAll(Countries.names(6)), c.addAll(c2), c , c);/* remove(): 移除某个元素 */c.remove(Countries.DATA[0][0]);print(c.remove(Countries.DATA[0][0]), c , c);c.remove(Countries.DATA[1][0]);print(c.remove(Countries.DATA[1][0]), c , c);/* removeAll(): 从c中移除c 和 c2 的交集元素 */print(c2 , c2);c.removeAll(c2);print(c.removeAll(c2), c , c);c.addAll(c2);print(c.addAll(c2), c c);/* contains(): 集合是否包含单个元素 */String val Countries.DATA[3][0];print(c.contains( val ) c.contains(val));/* containsAll(): 集合间是否存在包含关系 */print(c.containsAll(c2) c.containsAll(c2));/* subList(start, end)截取子集包括start不包括end */CollectionString c3 ((ListString) c).subList(3, 5);print(c3 ((ListString) c).subList(3, 5), c3 c3);/* retainAll(): 求两个集合的交集 */print(c2 , c2);c2.retainAll(c3);print(c2.retainAll(c3), c2 , c2);/* a.removeAll(b) 从a中移除a与b的交集 */c2.removeAll(c3);print(c2.removeAll(c3), c2.isEmpty() c2.isEmpty());c new ArrayListString();c.addAll(Countries.names(6));print(c.addAll(Countries.names(6)), c , c);c.clear(); // Remove all elementsprint(c.clear(), c c);} } // 打印结果 c [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI, ten, eleven] Collections.max(c) ten Collections.min(c) ALGERIA c2.addAll(Countries.names(6)), c.addAll(c2), c [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI, ten, eleven, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI] c.remove(Countries.DATA[0][0]), c [ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI, ten, eleven, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI] c.remove(Countries.DATA[1][0]), c [BENIN, BOTSWANA, BURKINA FASO, BURUNDI, ten, eleven, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI] c2 [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI] c.removeAll(c2), c [ten, eleven] c.addAll(c2), c [ten, eleven, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI] c.contains(BOTSWANA) true c.containsAll(c2) true c3 ((ListString) c).subList(3, 5), c3 [ANGOLA, BENIN] c2 [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI] c2.retainAll(c3), c2 [ANGOLA, BENIN] c2.removeAll(c3), c2.isEmpty() true c.addAll(Countries.names(6)), c [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI] c.clear(), c []【17.4】可选操作 1可选操作是什么 执行 各种不同的添加和移除的方法在 Collection接口中都是可选操作 2未获支持的操作这种方式可以实现java容器类库的一个重要目标 容器应该易学易用 3UnsupportedOperationException 未获支持的异常 3.1UnsupportedOperationException 必须是一种罕见事件。。大多数情况下 所有操作都应该是可以工作的只有在特例中才会有 未获支持的操作 3.2如果一个操作是未获支持的那么在实现接口时可能会导致 UnsupportedOperationException异常而不是把 程序交给客户之后才出现此异常这种情况是有道理的 3.3注意 未获支持的操作只有在运行时才能探测到因此它们表示动态类型检查 【17.4.1】未获支持的操作 【荔枝】当执行未获支持操作时抛出UnsupportedOperationException异常 public class Unsupported {static void test(String msg, ListString list) {System.out.println(--- msg ---);CollectionString c list;CollectionString subList list.subList(1, 8);// Copy of the sublist:CollectionString c2 new ArrayListString(subList);try {c.retainAll(c2);} catch (Exception e) {System.out.println(retainAll(): e);}try {c.removeAll(c2);} catch (Exception e) {System.out.println(removeAll(): e);}try {c.clear();} catch (Exception e) {System.out.println(clear(): e);}try {c.add(X);} catch (Exception e) {System.out.println(add(): e);}try {c.addAll(c2);} catch (Exception e) {System.out.println(addAll(): e);}try {c.remove(C);} catch (Exception e) {System.out.println(remove(): e);}// The List.set() method modifies the value but// doesnt change the size of the data structure:try {/* 对于Arrays.asList()生成的list 修改其某个index上的值是可以的 */list.set(0, X); } catch (Exception e) {System.out.println(List.set(): e);}}public static void main(String[] args) {ListString list Arrays.asList(A B C D E F G H I J K L.split( ));// 可修改的拷贝因为 new ArrayList 是利用list的基本数组数据 进行深度拷贝。test(Modifiable Copy, new ArrayListString(list)); System.out.println();// 这个listArrays$ArrayList 的基本数组 的 数据 是无法 改变的。test(Arrays.asList(), list); System.out.println();// 这是一种 不可修改的 拷贝同 new ArrayList()test(unmodifiableList(), Collections.unmodifiableList(new ArrayListString(list))); } } // 打印结果 --- Modifiable Copy ------ Arrays.asList() --- retainAll(): java.lang.UnsupportedOperationException removeAll(): java.lang.UnsupportedOperationException clear(): java.lang.UnsupportedOperationException add(): java.lang.UnsupportedOperationException addAll(): java.lang.UnsupportedOperationException remove(): java.lang.UnsupportedOperationException--- unmodifiableList() --- retainAll(): java.lang.UnsupportedOperationException removeAll(): java.lang.UnsupportedOperationException clear(): java.lang.UnsupportedOperationException add(): java.lang.UnsupportedOperationException addAll(): java.lang.UnsupportedOperationException remove(): java.lang.UnsupportedOperationException List.set(): java.lang.UnsupportedOperationException 【代码解说】 1因为Arrays.asList() 会生成一个 List它基于一个固定大小的数组仅支持哪些不会改变数组大小的操作对他而言是有道理的 2注意应该把Arrays.asList() 产生的list 作为构造器参数传给任何其他的 Collection推荐用 Collections.addAll() 方法这样就可以生成允许使用所有容器方法的 list了 3list.set(0, X) 可以看到 修改 Arrays.asList() 产生的list 的 某个元素的时候 是不会抛出异常的因为它并没有修改 list容器的大小 4Arrays.asList() 返回了固定尺寸的List 而 Collections.unmodifiableList() 产生不可修改的列表所以你会看见  当 list ArrayList.asList()的时候 list.set(0, X) 执行通过而当 list  Collections.unmodifiableList() 时则会抛出 java.lang.UnsupportedOperationException 未获支持的异常 【17.5】List的功能方法 1List的常用方法列表 add()方法添加对象get() 方法取出一个元素 调用 iterator() 方法获取遍历list的 迭代器 Iterator 【荔枝】List方法列表 public class Lists {private static boolean b;private static String s;private static int i;private static IteratorString it;private static ListIteratorString lit;public static void basicTest(String collectionName, ListString a) {print(\n// collectionName collectionName from basicTest method.);a.add(1, x); // Add at location 1(即第2个位置)a.add(x); // Add at endprint(a.add(1, \x\), a.add(\x\), a a);a.addAll(Countries.names(5));a.addAll(3, Countries.names(5));print(a.addAll(Countries.names(5)), a.addAll(3, Countries.names(5)), a a);b a.contains(1); // Is it in there?print(a.contains(\1\) b);// Is the entire collection in there?b a.containsAll(Countries.names(5));print(a.containsAll(Countries.names(5)) b);/* 以下操作成本对ArrayList很便宜对LinkedList很昂贵 */s a.get(1); // 取出 index 1 处的值i a.indexOf(1); // Tell index of objectb a.isEmpty(); // Any elements inside?it a.iterator(); // Ordinary Iteratorlit a.listIterator(); // ListIteratorlit a.listIterator(3); // Start at loc 3i a.lastIndexOf(1); // Last matchSystem.out.println(a.get(1) s , a.indexOf(\1\) i , a.isEmpty() b , a.iterator() it , a.listIterator(3) lit , a.lastIndexOf(\1\) a.lastIndexOf(1));print(a a);a.remove(1); // Remove location 1a.remove(3); // Remove this objecta.remove(tr);a.set(1, y); // Set location 1 to yprint(a.remove(1), a.remove(\3\), a.set(1, \y\), a a);/* retainAll() 求交集 */print(a a);a.retainAll(Countries.names(5)); print(Countries.names(5) Countries.names(5));print(a.retainAll(Countries.names(5)), a a);// Remove everything thats in the argument:a.removeAll(Countries.names(5));System.out.println(a.removeAll(Countries.names(5)), a a);i a.size(); // How big is it?a.clear(); // Remove all elements// mycode System.out.println( this is my mycode );a new ArrayList(Arrays.asList(A B C D E F G.split( )));List subList new ArrayList(Arrays.asList(A Z C I.split( )));print(a a);print(subList subList);a.retainAll(subList);print(a.retainAll(subList), a a);print(sublist subList);System.out.println(\n this is my mycode );a new ArrayList(Arrays.asList(A B C D E F G.split( )));subList new ArrayList(Arrays.asList(A Z C I.split( )));print(a a);print(subList subList);subList.retainAll(a);print(after subList.retainAll(a));print(a a);print(sublist subList);System.out.println( this is my mycode \nover);}/* 双向移动的迭代器 */public static void iterMotion(String collectionName, ListString a) {print(\n// collectionName collectionName , from iterMotion method);print(a a);ListIteratorString it a.listIterator(); // 双向移动的迭代器b it.hasNext();print(it.hasNext() b);b it.hasPrevious();print(it.hasPrevious() b);s it.next(); // 先返回值 后 counter.print(it.next() s);i it.nextIndex(); // 返回当值的 counter 大小print(it.nextIndex() i);s it.previous(); // --counter 先减 返回值 . print(it.previous() s); i it.previousIndex(); // --counter 先减print(it.previousIndex() i);}/* 通过迭代器操作容器元素增删改查 */public static void iterManipulation(String collectionName, ListString a) {print(\n// collectionName collectionName , from iterManipulation method);ListIteratorString it a.listIterator();print(a a);it.add(47);print(it.add(\47\), a a);it.next(); // 先返回值后更新游标 it.remove();// 移除游标的上一个元素然后更新游标 print(ListIterator.next(), ListIterator.remove(), a a);// Must move to an element after remove():/* remove 操作后必须调用next() 方法因为 remove() 把 lastRet 赋值为 -1 */it.next();// Change the element after the deleted one:it.set(47);print(a a);}public static void testVisual(String collectionName, ListString a) {print(\n// collectionName collectionName);print(a);ListString b Countries.names(5);print(b b);ArrayList list;a.addAll(b);a.addAll(b);print(a.addAll(b) a.addAll(b); a a);// Insert, remove, and replace elements// using a ListIterator:ListIteratorString x a.listIterator(a.size() / 2);x.add(one);print(x.add(one); a a);print(x.next());x.remove();print(x.next());x.set(47);print(a);// Traverse the list backwards:x a.listIterator(a.size());while (x.hasPrevious())printnb(x.previous() );print();print( testVisual finished \n);}// There are some things that only LinkedLists can do:public static void testLinkedList(String collectionName) {print(\n testLinkedList );LinkedListString ll new LinkedListString();ll.addAll(Countries.names(5));print(ll);// Treat it like a stack, pushing:ll.addFirst(one);ll.addFirst(two);print(ll);// Like peeking at the top of a stack:print(ll.getFirst());// Like popping a stack:print(ll.removeFirst());print(ll.removeFirst());// Treat it like a queue, pulling elements// off the tail end:print(ll.removeLast());print(ll);print( testLinkedList over.\n);}public static void main(String[] args) {// Make and fill a new list each time:basicTest(basicTest, LinkedList, new LinkedListString(Countries.names(5)));basicTest(basicTest, ArrayList, new ArrayListString(Countries.names(5)));iterMotion(iterMotion, LinkedList, new LinkedListString(Countries.names(5)));iterMotion(iterMotion, ArrayList, new ArrayListString(Countries.names(5)));iterManipulation(iterManipulation, LinkedList, new LinkedListString(Countries.names(5)));iterManipulation(iterManipulation, ArrayList, new ArrayListString(Countries.names(5)));testVisual(testVisual, LinkedList, new LinkedListString(Countries.names(5)));testLinkedList(testLinkedList);} } // 打印结果 // collectionName basicTest, LinkedListfrom basicTest method. a.add(1, x), a.add(x), a [ALGERIA, x, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, x] a.addAll(Countries.names(5)), a.addAll(3, Countries.names(5)), a [ALGERIA, x, ANGOLA, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, x, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a.contains(1) false a.containsAll(Countries.names(5)) true a.get(1) x, a.indexOf(1) -1, a.isEmpty() false, a.iterator() java.util.LinkedList$ListItr15db9742, a.listIterator(3) java.util.LinkedList$ListItr6d06d69c, a.lastIndexOf(1) -1 a [ALGERIA, x, ANGOLA, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, x, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a.remove(1), a.remove(3), a.set(1, y), a [ALGERIA, y, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, x, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a [ALGERIA, y, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, x, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] Countries.names(5) [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a.retainAll(Countries.names(5)), a [ALGERIA, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a.removeAll(Countries.names(5)), a []this is my mycode a [A, B, C, D, E, F, G] subList [A, Z, C, I] a.retainAll(subList), a [A, C] sublist [A, Z, C, I] this is my mycode a [A, B, C, D, E, F, G] subList [A, Z, C, I] after subList.retainAll(a) a [A, B, C, D, E, F, G] sublist [A, C]this is my mycode over// collectionName basicTest, ArrayListfrom basicTest method. a.add(1, x), a.add(x), a [ALGERIA, x, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, x] a.addAll(Countries.names(5)), a.addAll(3, Countries.names(5)), a [ALGERIA, x, ANGOLA, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, x, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a.contains(1) false a.containsAll(Countries.names(5)) true a.get(1) x, a.indexOf(1) -1, a.isEmpty() false, a.iterator() java.util.ArrayList$Itr7852e922, a.listIterator(3) java.util.ArrayList$ListItr4e25154f, a.lastIndexOf(1) -1 a [ALGERIA, x, ANGOLA, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, x, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a.remove(1), a.remove(3), a.set(1, y), a [ALGERIA, y, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, x, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a [ALGERIA, y, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, x, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] Countries.names(5) [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a.retainAll(Countries.names(5)), a [ALGERIA, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BENIN, BOTSWANA, BURKINA FASO, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a.removeAll(Countries.names(5)), a []this is my mycode a [A, B, C, D, E, F, G] subList [A, Z, C, I] a.retainAll(subList), a [A, C] sublist [A, Z, C, I] this is my mycode a [A, B, C, D, E, F, G] subList [A, Z, C, I] after subList.retainAll(a) a [A, B, C, D, E, F, G] sublist [A, C]this is my mycode over// collectionName iterMotion, LinkedList, from iterMotion method a [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] it.hasNext() true it.hasPrevious() false it.next() ALGERIA it.nextIndex() 1 it.previous() ALGERIA it.previousIndex() -1// collectionName iterMotion, ArrayList, from iterMotion method a [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] it.hasNext() true it.hasPrevious() false it.next() ALGERIA it.nextIndex() 1 it.previous() ALGERIA it.previousIndex() -1// collectionName iterManipulation, LinkedList, from iterManipulation method a [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] it.add(47), a [47, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] ListIterator.next(), ListIterator.remove(), a [47, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a [47, 47, BENIN, BOTSWANA, BURKINA FASO]// collectionName iterManipulation, ArrayList, from iterManipulation method a [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] it.add(47), a [47, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] ListIterator.next(), ListIterator.remove(), a [47, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a [47, 47, BENIN, BOTSWANA, BURKINA FASO]// collectionName testVisual, LinkedList [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] b [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] a.addAll(b) a.addAll(b); a [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] x.add(one); a [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, ALGERIA, ANGOLA, one, BENIN, BOTSWANA, BURKINA FASO, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] BENIN BOTSWANA [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, ALGERIA, ANGOLA, one, 47, BURKINA FASO, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] BURKINA FASO BOTSWANA BENIN ANGOLA ALGERIA BURKINA FASO 47 one ANGOLA ALGERIA BURKINA FASO BOTSWANA BENIN ANGOLA ALGERIA testVisual finished testLinkedList [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] [two, one, ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO] two two one BURKINA FASO [ALGERIA, ANGOLA, BENIN, BOTSWANA]testLinkedList over. 【17.6】Set和存储顺序 1Set需要一种方式来维护存储顺序。而存储顺序的维护依赖于Set的不同实现HashSet TreeSet 和 LinkedHashSet 2Set 基类 和 子类 2.1Set接口 存入 Set 的每个元素是唯一的Set 不保持重复元素。 加入Set 的元素必须重写 equals 方法 以确保对象唯一性 2.2HashSet* 默认选择优先推荐使用HashSet 为快速查找而设计的 Set。 存入HashSet 的元素重写 hashCode 方法 2.3TreeSet保持顺序的 Set 底层基于 红黑树实现。存入 TreeSet 的元素必须实现 Comparable接口 2.4LinkedHashSet 具有HashSet的 快速查询优点 内部使用链表维护元素顺序插入的次序。存入LinkedHashSet的元素重写 hashCode 方法 3重写 equals  和 hashCode 方法  3.1重写equals方法必须为 存入 HashSet 和  TreeSet  的元素 重写其 equals 方法 3.2重写 hashCode方法 当元素被存储到 HashSet 或 LinkedHashSet 中时必须重写元素的 hashCode 方法 建议 良好的编码风格是 同时重写 equals 方法 和 hashCode 方法 【荔枝-HashSet TreeSet LinkedHashSet存储规则】 // 存入Set的元素 必须重写 equals 方法 class SetType {int i;public SetType(int n) {i n;}/* 重写 equals 方法 */Overridepublic boolean equals(Object o) {return o instanceof SetType (i ((SetType) o).i);}public String toString() {return Integer.toString(i);} } /* 存入 HashSet的元素 */ class HashType extends SetType {public HashType(int n) {super(n);}/* 重写 hashCode 方法 */public int hashCode() {return i;} } /* 存入 TreeSet的元素 实现 Comparable 接口 */ class TreeType extends SetType implements ComparableTreeType {public TreeType(int n) {super(n);}Overridepublic int compareTo(TreeType arg) {return (arg.i i ? -1 : (arg.i i ? 0 : 1));} }public class TypesForSets {static T SetT fill(SetT set, ClassT type) {try {for (int i 0; i 10; i)set.add(type.getConstructor(int.class).newInstance(i));} catch (Exception e) {throw new RuntimeException(e);}return set;}static T void test(SetT set, ClassT type) {fill(set, type);fill(set, type); // Try to add duplicates, 不重复的。fill(set, type);System.out.println(set);}public static void main(String[] args) {test(new HashSetHashType(), HashType.class); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // 无序test(new LinkedHashSetHashType(), HashType.class); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 输出顺序和插入顺序同test(new TreeSetTreeType(), TreeType.class); // [9, 8, 7, 6, 5, 4, 3, 2, 1, 0], 按照排序规则有序System.out.println(\n\n);// Things that dont work: Set 存储不重复元素不起作用了凡是使用到 hash散列机制的容器必须重写该容器中存储元素的 hashCode 方法否则容器的存储规则不奏效test(new HashSetSetType(), SetType.class); // HashSet 添加 SetType元素而SetType 没有重写 hashCode() 方法test(new HashSetTreeType(), TreeType.class); // HashSet 添加 TreeType元素而TreeType 没有重写 hashCode() 方法test(new LinkedHashSetSetType(), SetType.class); // LinkedHashSet 添加 SetType元素而SetType 没有重写 hashCode() 方法test(new LinkedHashSetTreeType(), TreeType.class); // LinkedHashSet 添加 TreeType元素而TreeType 没有重写 hashCode() 方法System.out.println(\n\n);try {test(new TreeSetSetType(), SetType.class); // SetType 没有实现 Comparable接口不是Comparable子类所以插入TreeSet失败并抛出异常} catch (Exception e) {System.out.println(e.getMessage());}try {test(new TreeSetHashType(), HashType.class); // HashType 没有实现 Comparable接口不是Comparable子类所以插入TreeSet失败并抛出异常} catch (Exception e) {System.out.println(e.getMessage());}} } /* [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // 无序 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // 输出顺序和插入顺序同 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] // 按照排序规则有序[7, 3, 1, 9, 6, 5, 9, 1, 3, 8, 9, 0, 5, 2, 6, 1, 5, 4, 2, 0, 7, 4, 3, 8, 8, 7, 6, 4, 0, 2] [8, 0, 3, 9, 0, 2, 8, 5, 2, 3, 4, 1, 2, 9, 4, 1, 9, 6, 7, 7, 4, 1, 3, 8, 6, 5, 7, 5, 6, 0] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]java.lang.ClassCastException: chapter17.SetType cannot be cast to java.lang.Comparable java.lang.ClassCastException: chapter17.HashType cannot be cast to java.lang.Comparable */ 【代码解说】  解说1compareTo() 方法和equals() 方法的自然排序规则一致 equals 返回truecompareTo 方法返回 0equals 返回 false compareTo 方法返回 非0 解说2对于没有重写 hashCode() 方法的 SetType 或 TreeType 如果将他们放置到任何散列实现中都会产生重复值因为 HashSet 或 LinkedHashSet 中 重复的意义在于 元素的 哈希值或 hashCode 相同 【干货——HashSet 和 LinkedHashSet 底层采用 HashMap.key 进行存储元素因为 LinkedHashSet 继承 HashSet】 // HashSet 的构造器 和 Iterator() 方法源码public HashSet() {map new HashMap();} public HashSet(Collection? extends E c) {map new HashMap(Math.max((int) (c.size()/.75f) 1, 16));addAll(c);} public HashSet(int initialCapacity, float loadFactor) {map new HashMap(initialCapacity, loadFactor);} public HashSet(int initialCapacity) {map new HashMap(initialCapacity);} HashSet(int initialCapacity, float loadFactor, boolean dummy) {map new LinkedHashMap(initialCapacity, loadFactor);}public IteratorE iterator() {return map.keySet().iterator();} 【干货——TreeSet 底层采用 TreeMap.key 进行存储元素】 // TreeMap 的构造器 和 iterator() 方法源码 TreeSet(NavigableMapE,Object m) {this.m m;} public TreeSet() {this(new TreeMapE,Object());} public TreeSet(Comparator? super E comparator) {this(new TreeMap(comparator));}public TreeSet(Collection? extends E c) {this();addAll(c);}public TreeSet(SortedSetE s) {this(s.comparator());addAll(s);} public IteratorE iterator() {return m.navigableKeySet().iterator();}【荔枝-Object.equals() 和 hashCode() 方法源码】 // Object.equals() and hashCode() 源码public boolean equals(Object obj) {return (this obj);} public native int hashCode(); 4HashSet LinkedHashSet TreeSet 存储机制 HashSet 以某种散列机制 保持所有元素 LinkedHashSet 按照元素插入的顺序保存元素  TreeSet 按照排序顺序维护元素的次序 排序规则 通过 实现 Comparable接口并重写 compareTo() 方法来实现 【17.6.1】SortedSet 1介绍 SortedSet中的元素保证处于排序状态 其 comparator() 方法返回当前 Set 使用 的 Comparator或者返回null 表示 以自然方式排序 first() 返回第一个元素 last() 返回最后一个元素 subSet(from, to ) 生成set的子集 包含from 不包含 to headSet(to)  生成该set 的子集 且子集元素的值 小于 to 元素的值 tailSet(from)  生成该set 的子集 且子集元素的值 大于 或等于 from 元素的值 【荔枝-SortedSet方法演示】 public class SortedSetDemo {public static void main(String[] args) {SortedSetString sortedSet new TreeSetString();Collections.addAll(sortedSet,one two three four five six seven eight.split( ));print(sortedSet sortedSet); // sortedSet [eight, five, four, one, seven, six, three, two]String low sortedSet.first(); // 第一个元素String high sortedSet.last(); // 最后一个元素print(low low);print(high high);IteratorString it sortedSet.iterator(); // 迭代器for (int i 0; i 6; i) {if (i 3)low it.next();if (i 6)high it.next();elseit.next();}print(low); // oneprint(high); // twoprint(sortedSet.subSet(low, high)); // 子集包括low不包括high[one, seven, six, three]print(sortedSet.headSet(high)); // 元素值小于high的子集 [eight, five, four, one, seven, six, three]print(sortedSet.tailSet(low)); // 元素值大于等于low的子集[one, seven, six, three, two]print(sortedSet.comparator() sortedSet.comparator()); // sortedSet.comparator() null自然排序} } 【代码解说】SortedSet的排序 按照对象的比较函数值  对 元素排序 【17.7】队列 1Queue的实现 java SE5 中的实现是 LinkedList 和 PriorityQueue 它们的差异在于 排序行为而不是性能 /* Queue容器进队和出队的荔枝 */ public class QueueBehavior {private static int count 10;static T void test(QueueT queue, GeneratorT gen) {for (int i 0; i count; i)queue.offer(gen.next()); // 插入尾部offer() add() 方法while (queue.peek() ! null) // 不删除头部并返回头部 peek() 当queue为空返回空System.out.print(queue.remove() ); // 删除头部System.out.println();}static class Gen implements GeneratorString {String[] s (one two three four five six seven eight nine ten).split( );int i;public String next() {return s[i];}}public static void main(String[] args) {test(new LinkedListString(), new Gen()); // 出队顺序与进队顺序一致test(new PriorityQueueString(), new Gen()); // 不一致test(new ArrayBlockingQueueString(count), new Gen()); // 出队顺序与进队顺序一致test(new ConcurrentLinkedQueueString(), new Gen()); // 出队顺序与进队顺序一致test(new LinkedBlockingQueueString(), new Gen()); // 出队顺序与进队顺序一致test(new PriorityBlockingQueueString(), new Gen()); // 不一致} } 【代码解说】除了优先级队列 PriorityQueue 和 PriorityBlockingQueue 其他队列 将精确地按照进队顺序进行出队操作 【17.7.1】优先级队列 /* 优先级队列的荔枝 */ public class ToDoList extends PriorityQueueToDoList.ToDoItem {static class ToDoItem implements ComparableToDoItem { // 静态内部类private char primary;private int secondary;private String item;public ToDoItem(char pri, int sec, String item) {primary pri;secondary sec;this.item item;}/* 优先级计算规则 */public int compareTo(ToDoItem arg) {if (primary arg.primary)return 1;if (primary arg.primary)if (secondary arg.secondary)return 1;else if (secondary arg.secondary)return 0;return -1;}public String toString() {return Character.toString(primary) secondary : item ; ;}}public void add(String item, char pri, int sec) {super.add(new ToDoItem(pri, sec, item));}public static void main(String[] args) {ToDoList toDoList new ToDoList();toDoList.add(A4, C, 4);toDoList.add(A2, A, 2);toDoList.add(B7, B, 7);toDoList.add(C3, C, 3);toDoList.add(A1, A, 1);toDoList.add(B1, B, 1);while (!toDoList.isEmpty())System.out.print(toDoList.remove() );} } /* A1: A1; A2: A2; B1: B1; B7: B7; C3: C3; C4: A4; */ 【17.7.2】双向队列 1介绍 可以在双向队列双端队列 的任何一段添加 或 移除元素。LinkedList提供了支持 双向队列的方法但在java 标准类库中 没有任何显式 的用于双向队列的接口 2如何实现双向队列 使用组合来创建一个 Deque类 并直接中 LinkedList中暴露方法如下 // 这是 作者 自定义的 双向队列 Deque 该双向队列的底层基于 LinkedList public class DequeT {private LinkedListT deque new LinkedListT();public void addFirst(T e) {deque.addFirst(e);}public void addLast(T e) {deque.addLast(e);}public T getFirst() {return deque.getFirst();}public T getLast() {return deque.getLast();}public T removeFirst() {return deque.removeFirst();}public T removeLast() {return deque.removeLast();}public int size() {return deque.size();}public String toString() {return deque.toString();}// And other methods as necessary... 这里添加其他必须的方法 } // /:~ 【代码解说】首先 这个双向队列是 thinking-in-java 作者 自定义的并不是java 类库中的 且该自定义的 双向队列是基于 LinkedList来实现的 第二 Deque 双向队列没有 Queue 那样常用 【17.8】理解Map 1Map的几种基本实现 HashMap, TreeMap, LinkedHashMap, WeakHashMap, ConcurrentHashMap IdentityHashMap 等 2Map的简单荔枝 【荔枝-通过 2维数组 来实现 HashMap的键值对存储原理】 // 通过 2维数组 来实现 HashMap的键值对存储原理 public class AssociativeArrayK, V {Set set new HashSet();private Object[][] pairs;private int index;public AssociativeArray(int length) {pairs new Object[length][2];}public void put(K key, V value) {if (index pairs.length)throw new ArrayIndexOutOfBoundsException();pairs[index] new Object[] { key, value };}SuppressWarnings(unchecked)public V get(K key) {for (int i 0; i index; i)if (key.equals(pairs[i][0]))return (V) pairs[i][1];return null; // Did not find key}public String toString() {StringBuilder result new StringBuilder();for (int i 0; i index; i) {result.append(pairs[i][0].toString());result.append( : );result.append(pairs[i][1].toString());if (i index - 1)result.append(\n);}return result.toString();}public static void main(String[] args) {AssociativeArrayString, String map new AssociativeArrayString, String(6);map.put(sky, blue);map.put(grass, green);map.put(ocean, dancing);map.put(tree, tall);map.put(earth, brown);map.put(sun, warm);try {map.put(extra, object); // Past the end。当容器存储元素存满的时候继续插入元素抛出异常。} catch (ArrayIndexOutOfBoundsException e) {print(Too many objects!);}print(map map);print(map.get(\ocean\) map.get(ocean));} } /* Too many objects! map sky : blue grass : green ocean : dancing tree : tall earth : brown sun : warm map.get(ocean) dancing */ 【17.8.1】性能 1性能是映射表中的一个重要问题当在 get() 中使用线性搜索时执行速度回相当地慢这正是 HashMap 提高速度的地方 2散列码 HashMap 使用了特殊的值称作 散列码来取代对键的缓慢搜索 HashMap 使用对象的hashCode()方法进行快速查询的 3下面是Map的基本实现类其中HashMap 是默认选择 HashMapMap基于散列表实现取代了 Hashtable。通过构造器设置容量和负载因子以调整容器性能 LinkedHashMap使用链表维护内部次序其中输出顺序 是 其 插入顺序 或者是最近最少使用LRU, least recently used次序 TreeMap基于红黑树实现 被Comparable 或 Comparator 排序。TreeMap 是唯一有 subMap() 方法的Map 它可以返回一个子树 WeakHashMap 弱键映射允许释放映射所指向的对象 ConcurrentHashMap线程安全的Map 不涉及同步加锁 IdentityHashMap使用 代替 equals() 方法 对 键 进行比较的散列映射 4散列散列是映射中存储元素时最常用的方式 5任何Map容器所存储的元素必须满足以下要求任何键都必须重写  equals() 方法 如果存储在HashMap的元素 该元素还必须重写 hashCode()方法如果使用 TreeMap 来存储元素则元素必须实现 Comparable 【荔枝-Map实现类】 /* Map实现类的荔枝: HashMap, TreeMap, LinkedHashMap, ConcurrentHashMap, WeakHashMap */ public class Maps {Properties pro;public static void printKeys(MapInteger, String map) {printnb(map.size() map.size() , );printnb(map.keySet() );print(map.keySet()); // Produce a Set of the keys}public static void test(MapInteger, String map, String mapType) {System.out.println(\n mapType );print(map.getClass().getSimpleName() map.getClass().getSimpleName());map.putAll(new CountingMapData(5));// Map has Set behavior for keys:map.putAll(new CountingMapData(5));printKeys(map);// Producing a Collection of the values:printnb(map.values() );print(map.values());print(map map);print(map.containsKey(3) map.containsKey(3));print(map.get(3) map.get(3));print(map.containsValue(\C0\) map.containsValue(C0));Integer key map.keySet().iterator().next();print(First key in map key);map.remove(key);printKeys(map);map.clear();print(map.clear(), map.isEmpty() map.isEmpty());map.putAll(new CountingMapData(10));// Operations on the Set change the Map:map.keySet().removeAll(map.keySet());print(map.isEmpty(): map.isEmpty());}public static void main(String[] args) {test(new HashMapInteger, String(), HashMap);test(new TreeMapInteger, String(), TreeMap);test(new LinkedHashMapInteger, String(), LinkedHashMap);test(new IdentityHashMapInteger, String(), IdentityHashMap);test(new ConcurrentHashMapInteger, String(), ConcurrentHashMap);test(new WeakHashMapInteger, String(), WeakHashMap);} } /*HashMap map.getClass().getSimpleName() HashMap map.size() 5, map.keySet() [0, 1, 2, 3, 4] map.values(): [A0, B0, C0, D0, E0] map {0A0, 1B0, 2C0, 3D0, 4E0} map.containsKey(3): true map.get(3): D0 map.containsValue(C0): true First key in map: 0 map.size() 4, map.keySet() [1, 2, 3, 4] map.isEmpty(): true map.isEmpty(): trueTreeMap map.getClass().getSimpleName() TreeMap map.size() 5, map.keySet() [0, 1, 2, 3, 4] map.values(): [A0, B0, C0, D0, E0] map {0A0, 1B0, 2C0, 3D0, 4E0} map.containsKey(3): true map.get(3): D0 map.containsValue(C0): true First key in map: 0 map.size() 4, map.keySet() [1, 2, 3, 4] map.isEmpty(): true map.isEmpty(): trueLinkedHashMap map.getClass().getSimpleName() LinkedHashMap map.size() 5, map.keySet() [0, 1, 2, 3, 4] map.values(): [A0, B0, C0, D0, E0] map {0A0, 1B0, 2C0, 3D0, 4E0} map.containsKey(3): true map.get(3): D0 map.containsValue(C0): true First key in map: 0 map.size() 4, map.keySet() [1, 2, 3, 4] map.isEmpty(): true map.isEmpty(): trueIdentityHashMap map.getClass().getSimpleName() IdentityHashMap map.size() 5, map.keySet() [0, 2, 4, 3, 1] // 无序 map.values(): [A0, C0, E0, D0, B0] map {0A0, 2C0, 4E0, 3D0, 1B0} map.containsKey(3): true map.get(3): D0 map.containsValue(C0): false First key in map: 0 map.size() 4, map.keySet() [2, 4, 3, 1] map.isEmpty(): true map.isEmpty(): trueConcurrentHashMap map.getClass().getSimpleName() ConcurrentHashMap map.size() 5, map.keySet() [0, 1, 2, 3, 4] map.values(): [A0, B0, C0, D0, E0] map {0A0, 1B0, 2C0, 3D0, 4E0} map.containsKey(3): true map.get(3): D0 map.containsValue(C0): true First key in map: 0 map.size() 4, map.keySet() [1, 2, 3, 4] map.isEmpty(): true map.isEmpty(): trueWeakHashMap map.getClass().getSimpleName() WeakHashMap map.size() 5, map.keySet() [4, 3, 2, 1, 0] map.values(): [E0, D0, C0, B0, A0] map {4E0, 3D0, 2C0, 1B0, 0A0} map.containsKey(3): true map.get(3): D0 map.containsValue(C0): true First key in map: 4 map.size() 4, map.keySet() [3, 2, 1, 0] map.isEmpty(): true map.isEmpty(): true */ // Maps.java 调用了 CountingMapData 类 public class CountingMapData extends AbstractMapInteger, 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) {if (size 0)this.size 0;this.size size;}private static class Entry implements Map.EntryInteger, String {// 静态内部类int index;Entry(int index) {this.index index;}public boolean equals(Object o) {return Integer.valueOf(index).equals(o);}public Integer getKey() {return index;}public String getValue() {return chars[index % chars.length] Integer.toString(index / chars.length);}public String setValue(String value) {throw new UnsupportedOperationException();}public int hashCode() {return Integer.valueOf(index).hashCode();}}public SetMap.EntryInteger, String entrySet() {// LinkedHashSet retains initialization order: // LinkedHashSet 保持了初始化顺序。SetMap.EntryInteger, String entries new LinkedHashSetMap.EntryInteger, String();for (int i 0; i size; i)entries.add(new Entry(i));return entries;}public static void main(String[] args) {/*AbstractMap的toString() 方法调用了 entrySet().iterator() 迭代器*//* iteraotr迭代器 调用了 entry.getKey() 和 entry.getValue() 方法 */System.out.println(new CountingMapData(60));} } /** Output: {0A0, 1B0, 2C0, 3D0, 4E0, 5F0, 6G0, 7H0, 8I0, 9J0, 10K0,* 11L0, 12M0, 13N0, 14O0, 15P0, 16Q0, 17R0, 18S0, 19T0, 20U0, 21V0,* 22W0, 23X0, 24Y0, 25Z0, 26A1, 27B1, 28C1, 29D1, 30E1, 31F1, 32G1,* 33H1, 34I1, 35J1, 36K1, 37L1, 38M1, 39N1, 40O1, 41P1, 42Q1, 43R1,* 44S1, 45T1, 46U1, 47V1, 48W1, 49X1, 50Y1, 51Z1, 52A2, 53B2, 54C2,* 55D2, 56E2, 57F2, 58G2, 59H2}*/// :~ // CountingMapData extends AbstractMap, 调用的也是 AbstractMap的toString() //AbstractMap.toString() 源码public String toString() {IteratorEntryK,V i entrySet().iterator();if (! i.hasNext())return {};StringBuilder sb new StringBuilder();sb.append({);for (;;) {EntryK,V e i.next();K key e.getKey();V value e.getValue();sb.append(key this ? (this Map) : key);sb.append();sb.append(value this ? (this Map) : value);if (! i.hasNext())return sb.append(}).toString();sb.append(,).append( );}}【代码解说】Map容器中键必须是唯一的值可以重复【17.8.2】SortedMapTreeMap 是 SortedMap 现阶段的唯一实现 1使用SortedMap 确保键处于排序状态 2SortMap的方法列表如下 // 荔枝-SortedMap 方法列表 public class SortedMapDemo {public static void main(String[] args) {TreeMapInteger, String sortedMap new TreeMapInteger, String(new CountingMapData(10));print(sortedMap sortedMap); // sortedMap {0A0, 1B0, 2C0, 3D0, 4E0, 5F0, 6G0, 7H0, 8I0, 9J0}Integer low sortedMap.firstKey(); // 第一个键Integer high sortedMap.lastKey(); // 最后一个键print(sortedMap.firstKey() low);print(sortedMap.lastKey() high);IteratorInteger it sortedMap.keySet().iterator();for (int i 0; i 6; i) {if (i 3)low it.next();if (i 6)high it.next();elseit.next();}print(low low); // low 3print(high high); // high 7print(sortedMap.subMap(low, high) sortedMap.subMap(low, high));print(sortedMap.headMap(high) sortedMap.headMap(high));print(sortedMap.tailMap(low) sortedMap.tailMap(low));} } /* sortedMap {0A0, 1B0, 2C0, 3D0, 4E0, 5F0, 6G0, 7H0, 8I0, 9J0} sortedMap.firstKey() 0 sortedMap.lastKey() 9 low 3 high 7 sortedMap.subMap(low, high) {3D0, 4E0, 5F0, 6G0}map子集包括low3不包括high7 sortedMap.headMap(high) {0A0, 1B0, 2C0, 3D0, 4E0, 5F0, 6G0}map子集键值小于high的键值对子集 sortedMap.tailMap(low) {3D0, 4E0, 5F0, 6G0, 7H0, 8I0, 9J0}map子集键值大于等于low的键值对子集 */ sortedMap.subMap(low, high) map子集包括low3不包括high7 sortedMap.headMap(high)map子集键值小于high的键值对子集 sortedMap.tailMap(low) map子集键值大于等于low的键值对子集 【17.8.3】LinkedHashMap 1为了提高速度 LinkedHashMap 散列化所有元素 遍历键值对的顺序 与 元素的插入顺序相同 或 最近最少使用LRU顺序 2LinkedHashMap 演示荔枝 // 荔枝-LinkedHashMap 演示 public class LinkedHashMapDemo {public static void main(String[] args) {LinkedHashMapInteger, String linkedHashMap new LinkedHashMapInteger, String(new CountingMapData(9));print(linkedHashMap1 linkedHashMap);// Least-recently-used order: 最近最少使用 LRU 顺序linkedHashMap new LinkedHashMapInteger, String(16, 0.75f, true);linkedHashMap.putAll(new CountingMapData(9));print(linkedHashMap2 linkedHashMap);for (int i 0; i 6; i)// Cause accesses:linkedHashMap.get(i);// 最近最少使用顺序0,1,2,3,4,5 分别先后被使用过而6,7,8没有被使用所以 LRU 6, 7, 8, 0, 1, 2, 3, 4, 5,print(linkedHashMap3 linkedHashMap); linkedHashMap.get(0);print(linkedHashMap4 linkedHashMap); // 键为0的元素被使用过所以键0的entry 排到了最后} } /* linkedHashMap1 {0A0, 1B0, 2C0, 3D0, 4E0, 5F0, 6G0, 7H0, 8I0} linkedHashMap2 {0A0, 1B0, 2C0, 3D0, 4E0, 5F0, 6G0, 7H0, 8I0} linkedHashMap3 {6G0, 7H0, 8I0, 0A0, 1B0, 2C0, 3D0, 4E0, 5F0} linkedHashMap4 {6G0, 7H0, 8I0, 1B0, 2C0, 3D0, 4E0, 5F0, 0A0} */ 【17.9】散列与散列码Hash 和 hashCode public class Groundhog {protected int number;public Groundhog(int n) {number n;}public String toString() {return Groundhog # number;} } // /:~ 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!;elsereturn Early Spring!;} } // /:~ // HashMap荔枝-以Groundhog作为keyPrediction作为value public class SpringDetector {// Uses a Groundhog or class derived from Groundhog:// 使用 Groundhog 或 其子类 的class 作为 typepublic static T extends Groundhog void detectSpring(ClassT type)throws Exception {// 获取构造器采用反射机制来创建 HashMap.key ConstructorT ghog type.getConstructor(int.class);// 以Groundhog作为keyPrediction作为valueMapGroundhog, Prediction map new HashMapGroundhog, Prediction();for (int i 0; i 10; i)map.put(ghog.newInstance(i), new Prediction());print(map map); // 打印map调用map中每个entry的key 和 value的toString()方法Groundhog gh ghog.newInstance(3);print(ghog.newInstance(3) gh);if (map.containsKey(gh))print(map.get(gh) map.get(gh));elseprint(Key not found: gh);}public static void main(String[] args) throws Exception {detectSpring(Groundhog.class);} } /* map {Groundhog #1Six more weeks of Winter!, Groundhog #4Six more weeks of Winter!, Groundhog #5Early Spring!, Groundhog #3Early Spring!, Groundhog #8Six more weeks of Winter!, Groundhog #7Early Spring!, Groundhog #0Six more weeks of Winter!, Groundhog #2Early Spring!, Groundhog #9Six more weeks of Winter!, Groundhog #6Early Spring!} ghog.newInstance(3) Groundhog #3 Key not found: Groundhog #3 */ // AbstractMap.toString() 方法源码 public String toString() {IteratorEntryK,V i entrySet().iterator();if (! i.hasNext())return {};StringBuilder sb new StringBuilder();sb.append({);for (;;) {EntryK,V e i.next();K key e.getKey();V value e.getValue();sb.append(key this ? (this Map) : key);sb.append();sb.append(value this ? (this Map) : value);if (! i.hasNext())return sb.append(}).toString();sb.append(,).append( );}}【代码解说】 SpringDetector.java 中 HashMap 明明插入了 number3的 Groundhog 实例 为什么以 number3的Groundhog 实例 为键 无法查询到 其value 因为 Groundhog 自动继承自基类 Object所以这里使用了 Object.hashCode() 方法生成散列码而hashCode() 返回结果默认 使用对象的地址计算散列码 1HashMap 使用 equals() 方法 判断当前的键是否与表中存在的键相同 2正确的 equals() 方法必须满足下面5个条件 自反性 x.equals(x) 一定返回 true 对称性x.equals(y) y.equals(x)  true or false 传递性x.equals(y) true 和 y.equals(z) true 则推出   x.equals.(z) true 一致性如果对象中用于等价比较的信息没有改变则 无论调用  x.equals(y) 多少次返回的结果应该保持一致要么一直是true 或者一直 是 false 对任何不是 null 的x x.equals(null) 一定返回 false 3Object.hashCode 和 Object.equals() 方法的默认实现 equals()方法默认  比较对象的地址 hashCode()方法默认 使用对象的地址计算散列码 // Object.equals() 和 Object.hashCode() 源码public boolean equals(Object obj) {return (this obj);} public native int hashCode(); 【干货】如果要使用自己的类作为 HashMap的键必须重载或重写 hashCode() 和 equals() 方法 4hashCode() 和 equals() 方法的区别在于 hashCode方法用于计算键的散列码并给元素分配对应散列码的存储位置 equals 是比较两个键值对间的 键 是否相同 【荔枝- HashMap荔枝-以Groundhog2作为keyPrediction作为value并重写了Groundhog2的 hashCode() 和 equals() 方法】 public class Groundhog2 extends Groundhog {public Groundhog2(int n) {super(n);}// 重写 hashCode() 方法Overridepublic int hashCode() {return number;}// 重写 equals() 方法Overridepublic boolean equals(Object o) {return o instanceof Groundhog2 (number ((Groundhog2) o).number);} } // 荔枝- HashMap荔枝-以Groundhog2作为keyPrediction作为value并重写了Groundhog2的 hashCode() 和 equals() 方法 // 现在可以找到键3的value了 public class SpringDetector2 {public static void main(String[] args) throws Exception {SpringDetector.detectSpring(Groundhog2.class);} } /* map {Groundhog #0Six more weeks of Winter!, Groundhog #1Six more weeks of Winter!, Groundhog #2Early Spring!, Groundhog #3Early Spring!, Groundhog #4Six more weeks of Winter!, Groundhog #5Early Spring!, Groundhog #6Early Spring!, Groundhog #7Early Spring!, Groundhog #8Six more weeks of Winter!, Groundhog #9Six more weeks of Winter!} ghog.newInstance(3) Groundhog #3 ( 已经可以找到键3的value了) map.get(gh) Early Spring! */ 【代码解说】instanceof关键字 instanceof 检查了此对象是否为null 如果instanceof 左边的对象为null 则instanceof 会返回 false 【17.9.1】理解hashCode()  1散列的目的在于 想要使用一个对象查找另外一个对象 2 荔枝-使用 一对ArrayList 实现 Map // 使用 一对ArrayList 实现 Map public class SlowMapK, V extends AbstractMapK, V {private ListK keys new ArrayListK();private ListV values new ArrayListV();public V put(K key, V value) {V oldValue get(key); // The old value or nullif (!keys.contains(key)) {keys.add(key);values.add(value);} elsevalues.set(keys.indexOf(key), value);return oldValue;}// key的数据类型为 Object 而不是 泛型 K 类型public V get(Object key) { // key is type Object, not Kif (!keys.contains(key))return null;return values.get(keys.indexOf(key));}public SetMap.EntryK, V entrySet() {SetMap.EntryK, V set new HashSetMap.EntryK, V(); // EntrySet 容器IteratorK ki keys.iterator();IteratorV vi values.iterator();while (ki.hasNext())set.add(new MapEntryK, V(ki.next(), vi.next()));return set;}public static void main(String[] args) {SlowMapString, String m new SlowMapString, String();m.putAll(Countries.capitals(5));System.out.println(m.putAll(Countries.capitals(5)), m m);System.out.println(m.get(\BULGARIA\) m.get(BULGARIA));System.out.println(m.entrySet() m.entrySet());} } /* m.putAll(Countries.capitals(5)), m {ANGOLALuanda, BURKINA FASOOuagadougou, BENINPorto-Novo, ALGERIAAlgiers, BOTSWANAGaberone} m.get(BULGARIA) null m.entrySet() [ANGOLALuanda, BURKINA FASOOuagadougou, BENINPorto-Novo, ALGERIAAlgiers, BOTSWANAGaberone] */【代码解说】 Map.entrySet() 方法必须产生一个 Map.entry 对象集 3如果想要创建自己的 Map 类型 就必须同时定义 Map.Entry 的实现 【荔枝-定义自己的 MapEntry类型且必须实现 Map.Entry 接口】 // 定义自己的 MapEntry类型且必须实现 Map.Entry 接口 public class MapEntryK, V implements Map.EntryK, V {private K key;private V value;public MapEntry(K key, V value) {this.key key;this.value value;}public K getKey() {return key;}public V getValue() {return value;}public V setValue(V v) {V result value;value v;return result;}// 重写 hashCode 方法Overridepublic int hashCode() {return (key null ? 0 : key.hashCode())^ (value null ? 0 : value.hashCode());}// 重写 equals 方法Overridepublic boolean equals(Object o) {if (!(o instanceof MapEntry))return false;MapEntry me (MapEntry) o;return (key null ? me.getKey() null : key.equals(me.getKey())) (value null ? me.getValue() null : value.equals(me.getValue()));}public String toString() {return key value;} } // /:~ 【代码解说】 entrySet() 方法使用了 HashSet 来保持 键值对 并且MapEntry 只使用了 key的hashCode() 方法 以上自定义的 MapEntry 不是一个恰当的实现 因为它创建了 键值对的副本。。entrySet() 的切当实现应该在 Map 中提供视图 而不是副本 并且这个视图允许对原始映射表进行修改副本就不行。。 【HashMap.Entry 定义源码】 【17.9.2】 为速度而散列 1散列的价值在于速度散列使得查询得以快速进行 2哈希冲突由外部链接处理数组并不直接保存值而是保存值的 list。然后对list 中的值使用 equals() 方法进行线性查询。如果散列函数好的话list 所存储的值就很少 list保存着 散列码相同的元素。 3基于LinkedList自定义HashMap的荔枝 // 基于LinkedList自定义HashMap的荔枝 public class SimpleHashMapK, V extends AbstractMapK, V {private HashMap map;// Choose a prime number for the hash table// size, to achieve a uniform distribution:static final int SIZE 997; // 设置hashmap的大小为质数// You cant have a physical array of generics,// but you can upcast to one:SuppressWarnings(unchecked)// HashMap 通过 LinkedList 来实现LinkedListMapEntryK, V[] buckets new LinkedList[SIZE];// 插入或更新如果有的话则更新没有的话则插入public V put(K key, V value) {V oldValue null;int index Math.abs(key.hashCode()) % SIZE; // 散列函数计算散列码if (buckets[index] null) // 每个数组元素不是 保存值而是保存值的链表list.buckets[index] new LinkedListMapEntryK, V();LinkedListMapEntryK, V bucket buckets[index];MapEntryK, V pair new MapEntryK, V(key, value);boolean found false;ListIteratorMapEntryK, V it bucket.listIterator();while (it.hasNext()) {MapEntryK, V iPair it.next();if (iPair.getKey().equals(key)) {oldValue iPair.getValue();it.set(pair); // Replace old with newfound true;break;}}if (!found)buckets[index].add(pair);return oldValue;}// 通过键获取值public V get(Object key) {int index Math.abs(key.hashCode()) % SIZE;if (buckets[index] null)return null;for (MapEntryK, V iPair : buckets[index])if (iPair.getKey().equals(key))return iPair.getValue();return null;}public SetMap.EntryK, V entrySet() {SetMap.EntryK, V set new HashSetMap.EntryK, V();for (LinkedListMapEntryK, V bucket : buckets) {if (bucket null)continue;for (MapEntryK, V mpair : bucket)set.add(mpair);}return set;}public static void main(String[] args) {SimpleHashMapString, String m new SimpleHashMapString, String();m.putAll(Countries.capitals(5));System.out.println(m m);System.out.println(m.get(\BENIN\) m.get(BENIN));System.out.println(m.entrySet() m.entrySet());} } /* m {ANGOLALuanda, BURKINA FASOOuagadougou, BENINPorto-Novo, ALGERIAAlgiers, BOTSWANAGaberone} m.get(BENIN) Porto-Novo m.entrySet() [ANGOLALuanda, BURKINA FASOOuagadougou, BENINPorto-Novo, ALGERIAAlgiers, BOTSWANAGaberone] */// 定义自己的 MapEntry类型且必须实现 Map.Entry 接口 public class MapEntryK, V implements Map.EntryK, V {private K key;private V value;public MapEntry(K key, V value) {this.key key;this.value value;}public K getKey() {return key;}public V getValue() {return value;}public V setValue(V v) {V result value;value v;return result;}// 重写 hashCode 方法Overridepublic int hashCode() {return (key null ? 0 : key.hashCode())^ (value null ? 0 : value.hashCode());}// 重写 equals 方法Overridepublic boolean equals(Object o) {if (!(o instanceof MapEntry))return false;MapEntry me (MapEntry) o;return (key null ? me.getKey() null : key.equals(me.getKey())) (value null ? me.getValue() null : value.equals(me.getValue()));}public String toString() {return key value;} } // /:~ 【编码技巧】为使散列分布均匀 bucket桶的数量通常使用 质数 【17.9.3】覆盖hashCode() 方法 1buckets数组下标值 依赖于具体的 HashMap对象的容量 而容量的改变依赖于与容器的充满程度 和 负载因子有关。 2hashCode() 生成的结果经过处理后成为桶的下标如取模 3设计hashCode() 方法最重要的因素 无论何时 对同一个对象调用hashCode() 都应该生成同样的值 4String 和 hashCode()方法的荔枝String有个特点 如果程序中有多个String对象 都包含相同的字符串序列那么这些 String 对象都映射到同一块内存区域 看个荔枝 String s1 abc; String s2 abc; String s3 new String(abc); String s4 new String(abc); public class StringHashCode {public static void main(String[] args) {String[] hellos Hello Hello.split( );System.out.println(hellos[0].hashCode()); //System.out.println(hellos[1].hashCode());} } /* hashCode 相同 69609650 69609650*/5散列码5.1散列码的生成范围不重要只要是int就行了。。好的hashCode() 函数应该产生分布均匀的散列码5.2散列码不必是独一无二的应该更关注速度而不是唯一性但是通过 hashCode() 和 equals() 方法必须能够完全确定对象的身份6如何写出一份像样的 hashCode() 方法实现共5个步骤【荔枝-根据以上5个步骤重写 hashCode() 方法】// 荔枝-根据Joshua Bloch的指导意见重写 存入Map容器的元素的 hashCode() 方法 public class CountedString {private static ListString created new ArrayListString();private String s;private int id 0;public CountedString(String str) {s str;created.add(s);// id is the total number of instances// of this string in use by CountedString:for (String s2 : created)if (s2.equals(s))id;}public String toString() {return key { s , id id , hashCode() hashCode() }, value ;}// 重写 hashCode() 方法根据Joshua Bloch的指导意见重写hashCode() 方法public int hashCode() {int result 17; // 给int变量 result 赋予某个非零常量如17result 37 * result s.hashCode(); // 为对象内每个有意义的域计算一个int类型的散列码s.hashCoderesult 37 * result id; // 合并计算得到的散列码return result;}// 重写 equals() 方法public boolean equals(Object o) {return o instanceof CountedString s.equals(((CountedString) o).s) id ((CountedString) o).id;}public static void main(String[] args) {MapCountedString, Integer map new HashMapCountedString, Integer();CountedString[] cs new CountedString[5];for (int i 0; i cs.length; i) {cs[i] new CountedString(hi);map.put(cs[i], i); // Autobox int - Integer}print(map map);for (CountedString cstring : cs) {print(Looking up cstring cstring , map.get(cstring) map.get(cstring));}} } /* map {key {hi , id 4 , hashCode() 146450}, value 3, key {hi , id 5 , hashCode() 146451}, value 4, key {hi , id 2 , hashCode() 146448}, value 1, key {hi , id 3 , hashCode() 146449}, value 2, key {hi , id 1 , hashCode() 146447}, value 0} Looking up cstring key {hi , id 1 , hashCode() 146447}, value , map.get(cstring) 0 Looking up cstring key {hi , id 2 , hashCode() 146448}, value , map.get(cstring) 1 Looking up cstring key {hi , id 3 , hashCode() 146449}, value , map.get(cstring) 2 Looking up cstring key {hi , id 4 , hashCode() 146450}, value , map.get(cstring) 3 Looking up cstring key {hi , id 5 , hashCode() 146451}, value , map.get(cstring) 4 */【荔枝】重写 equals() hashCode() compareTo() 方法// 根据Joshua Bloch的指导意见重写 存入Map容器的元素的 hashCode() 方法 public class Individual implements ComparableIndividual {private static long counter 0;private final long id counter;private String name;public Individual(String name) {this.name name;}// name is optional:public Individual() {}public String toString() {return getClass().getSimpleName() (name null ? : name);}public long id() {return id;}// 重写 equals() 方法Overridepublic boolean equals(Object o) {return o instanceof Individual id ((Individual) o).id;}// 重写 hashCode() 方法注意 hashCode() 方法的实现方式Overridepublic int hashCode() {int result 17; // 给int变量 result 赋予某个非零常量如17if (name ! null)result 37 * result name.hashCode(); // 为对象内每个有意义的域计算一个int类型的散列码s.hashCoderesult 37 * result (int) id; // 合并计算得到的散列码return result; }// 实现 Comparable 接口并重写 compareTo() 方法Overridepublic int compareTo(Individual arg) {// Compare by class name first:String first getClass().getSimpleName();String argFirst arg.getClass().getSimpleName();int firstCompare first.compareTo(argFirst); // 1.第一次比较 if (firstCompare ! 0)return firstCompare;if (name ! null arg.name ! null) {// 2.若第一次比较没有结果则进行第二次比较int secondCompare name.compareTo(arg.name);if (secondCompare ! 0)return secondCompare;}// 3. 若类型无法比较两则大小则用 id 进行比较return (arg.id id ? -1 : (arg.id id ? 0 : 1));} } // /:~【编程技巧】为新类编写正确的 hashCode() 和 equals() 方法是很需要技巧的 【17.10】选择接口的不同实现 1容器列表 Map, List, Set 和 Queue 2遗留类 Hashtable Vector Stack 是过去遗留下来的类目的只是为了支持老程序不建议使用 【17.10.1】性能测试框架 【17.10.2】对List的选择 1get() 和 set() 方法的随机访问 1.1背后有数组支撑的 List 和 ArrayList无论列表的大小如何这些访问都很快速和一致 // ArrayList.set() and get() 源码 public E set(int index, E element) {rangeCheck(index);E oldValue elementData(index);elementData[index] element;return oldValue;} public E get(int index) {rangeCheck(index);return elementData(index);} 1.2对于LinkedList访问时间对于较大列表明显增加。。如果你需要执行大量 的随机访问不建议时间 LinkedList // LinkedList.set() and get() 源码 public E set(int index, E element) {checkElementIndex(index);NodeE x node(index); // for 循环遍历E oldVal x.item;x.item element;return oldVal;} public E get(int index) {checkElementIndex(index);return node(index).item;} 2add()方法在列表中间插入新元素 2.1ArrayList.add()当列表变大时 ArrayList的开销变大 // ArrayList.add() 源码 public void add(int index, E element) {rangeCheckForAdd(index);ensureCapacityInternal(size 1); // Increments modCount!!System.arraycopy(elementData, index, elementData, index 1,size - index);elementData[index] element;size;} 2.2LinkedList.add()当列表变大时而LinkedList的开销一直都很低廉 // LinkedList.add() 源码public void add(int index, E element) {checkPositionIndex(index);if (index size)linkLast(element);elselinkBefore(element, node(index));} 3insert 和 remove() 操作 3.1ArrayList插入和移除代价特别高昂并且其代价随列表尺寸的增加而增加 // ArrayList.remove() 源码 public E remove(int index) {rangeCheck(index);modCount;E oldValue elementData(index);int numMoved size - index - 1;if (numMoved 0)System.arraycopy(elementData, index1, elementData, index,numMoved);elementData[--size] null; // clear to let GC do its workreturn oldValue;} 3.2LinkedList插入和移除代价特别低廉 并且不随列表尺寸发生变化 // LinkedList.remove() 源码 public E remove() {return removeFirst();}public E removeFirst() {final NodeE f first;if (f null)throw new NoSuchElementException();return unlinkFirst(f);} private E unlinkFirst(NodeE f) {// assert f first f ! null;final E element f.item;final NodeE next f.next;f.item null;f.next null; // help GCfirst next;if (next null)last null;elsenext.prev null;size--;modCount;return element;} // 或者 remove(i) public E remove(int index) {checkElementIndex(index);return unlink(node(index));} 【17.10.3】微基准测试的危险 1微基准测试的注意事项 1.1不能做太多的假设且将你的测试窄化 1.2确保测试程序运行足够长时间 以产生有意义的数据并且要考虑到 某些 java hotspot技术只有在 程序运行了一段时间后才会踢爆问题 2剖析器可以把性能分析工作做得很好。java剖析器MinView.net/Books/BetterJava 或 其他开源的剖析器 3经验证 Math.random() 的范围是 [0,1): 【17.10.4】对Set的选择基于HashMap的HashSet 基于TreeMap的TreeSet 基于LinkedHashMap 的 LinkedHashSet 1HashSet 优于 TreeSet 特别是添加 和 查询元素时 2TreeSet 存在的唯一原因它可以维持元素的排序状态所以当需要一个排好序的Set时 才应该使用 TreeSet 容器因为TreeSet 内部支持排序并且因为迭代是更有可能执行的操作所以 TreeSet 迭代 速度 优于 HashSet 3注意插入操作 HashSet 优于 LinkedHashSet 因为这是由 维护链表所带来额外开销造成的 【17.10.5】对Map的选择 1除了 IdentityHashMap 所有的Map 实现的插入操作都会随着 Map 尺寸的变大 而明显变慢查找的代价小很多 2Hashtable 与 HashMap 性能相当 因为HashMap 是用来 代替 Hashtable 的因此它们使用了相同的底层存储和查找机制 3TreeMap 比 HashMap 要慢TreeMap是创建有序列表的方式 3.1TreeMap 查找键的流程 调用 TreeMap.keySet() 方法来获取键的Set 视图然后调用 toArray() 来产生由这些键构成的数组。。之后你可以使用静态方法 Arrays.binarySearch() 在排序数组中快速查找对象 3.2HashMap 查找键的流程HashMap 本身就被设计为 可以快速查找键 优先推荐使用 HashMap 查找除非 HashMap 没有使用的情况下使用TreeMap的查找键的方式 4插入效率LinkedHashMap 比 HashMap 慢 因为它维护散列数据结构的同时还要维护 链表以保持插入顺序 5IdentityHashMap 使用 而不是 equals() 来比较元素 【HashMap的性能因子】 1几个术语容量桶的个数初始容量表在在创建时所拥有的桶个数尺寸当前被存储的桶的数量负载因子 尺寸/ 容量2指定负载因子 HashMap 和 HashSet 都允许指定负载因子在构造器中表示当负载情况达到该负载因子的水平时 容器将自动增加其容量桶个数实现方式是使桶的容量加倍并重新将现有对象分布到新的桶位集中再散列3默认负载因子 HashMap的默认 负载因子是 0.75 表示当表的负载率达到 0.75时 才进行再散列4负载因子的影响 高负载因子可以降低表所需要的空间但是会增加查找代价这非常重要因为查找操作是 用的比较多的 操作5如何避免再散列的开销 如果知道在 HashMap中存储多少项 那么创建一个具有恰当大小的初始容量 可以避免 再散列【17.11】实用方法1容器的方法列表 被表示为java.util.Collections 类内部的静态方法 如下 【注意】min() 和 max( 方法 只能作用于 Collection对象 而不能作用于 List所以你不要担心 Collection是否应该被排序 只有在 执行bianrySearch 之前 才确实需要对 List 或 数组进行排序 【荔枝-Collections容器工具方法列表】 // 荔枝-Collections 容器工具方法列表 public class Utilities {/* Arrays.asList() 产生是list大小是固定的不能执行add() 操作会抛异常但是可以修改即set() 操作*/static ListString list Arrays.asList(one Two three Four five six one.split( ));public static void main(String[] args) {print(list list);// Collections.disjoint(c1,c2)当两个集合没有相同元素时返回true. disjoint 互斥不相交的 // Collections.singletonList(Four): 产生不可变的Set, List, Map 它们都只包含基于给定参数的内容而形成的单一项print(Collections.disjoint(list, Collections.singletonList(\Four\)) Collections.disjoint(list, Collections.singletonList(Four)));// Collections.max() 求最大元素 默认字符大小写敏感print(Collections.max(list) Collections.max(list));// Collections.min() 求最小元素 默认字符大小写敏感print(Collections.min(list) Collections.min(list));// Collections.max(list, String.CASE_INSENSITIVE_ORDER)) 在不考虑字母大小写敏感的基础上求最大元素print(Collections.max(list, String.CASE_INSENSITIVE_ORDER) Collections.max(list, String.CASE_INSENSITIVE_ORDER));// Collections.min(list, String.CASE_INSENSITIVE_ORDER)) 在不考虑字母大小写敏感的基础上求最小元素print(Collections.min(list, String.CASE_INSENSITIVE_ORDER) Collections.min(list, String.CASE_INSENSITIVE_ORDER));// Arrays.asList() 产生是list大小是固定的ListString sublist Arrays.asList(Four five six.split( ));print(Arrays.asList(\Four five six\.split(\ \)) sublist);// Collections.indexOfSubList(list, sublist) 返回sublist在list中第一次出现的位置或者找不到时返回 -1print(Collections.indexOfSubList(list, sublist) Collections.indexOfSubList(list, sublist)); // 返回3注意// Collections.lastIndexOfSubList(list, sublist) 返回sublist在list中最后一次出现的位置或者找不到时返回 -1print(Collections.lastIndexOfSubList(list, sublist) Collections.lastIndexOfSubList(list, sublist)); // 返回3注意// Collections.replaceAll(list, one, Yo), 用 Yo 替换 list中的所有 oneCollections.replaceAll(list, one, Yo);print(Collections.replaceAll(list, \one\, \Yo\), list list);// Collections.reverse(list), 逆转list中所有元素的顺序Collections.reverse(list);print(Collections.reverse(list), list list);// Collections.rotate(list, 3); 所有元素向后移动 3个位置并将末尾的元素循环移到前面去Collections.rotate(list, 3);print(Collections.rotate(list, 3), list list);ListString source Arrays.asList(in the matrix.split( ));print(Arrays.asList(\in the matrix\.split(\ \)) source source);// Collections.copy(list, source) 将source中的元素复制到list中从位置0开始复制若source元素数量小于list则list后面的元素会保留Collections.copy(list, source);print(Collections.copy(list, source), list list);// Collections.swap(list, i, j), 交换list中 位置i 和位置j 的元素Collections.swap(list, 0, list.size() - 1);print(Collections.swap(list, 0, list.size() - 1), list list);// Collections.shuffle(list, new Random(47)), 随机改变指定列表的顺序, 也可以不指定 Random而使用默认的RandomCollections.shuffle(list, new Random(47));print(Collections.shuffle(list, new Random(47)), list list);// Collections.fill(list, pop), 用 pop 替换list中的所有元素Collections.fill(list, pop);print(Collections.fill(list, \pop\), list list);// Collections.frequency(list, pop)返回list中 等于 pop 的元素个数print(Collections.frequency(list, \pop\) Collections.frequency(list, pop));// Collections.nCopies(3, snap), 返回大小为3的 且大小和值均不可改变的List 所有元素都引用 snapListString dups Collections.nCopies(3, snap);print(Collections.nCopies(3, \snap\) dups dups);// Collections.disjoint(list, dups) 两个集合如果不相交没有交集返回true 否则返回falseprint(Collections.disjoint(list, dups) Collections.disjoint(list, dups));print(Collections.disjoint(list, dups), list list);// Collections.enumeration(dups) 为参数dups 生成一个 旧式 枚举类EnumerationString e Collections.enumeration(dups);print(EnumerationString e Collections.enumeration(dups), e );VectorString v new VectorString();while (e.hasMoreElements()) {String s e.nextElement();print(s);v.addElement(s); // 把元素插入 vector}// Converting an old-style Vector to a List via an Enumeration:// 通过一个老式枚举类 把一个老式 Vector 转换为 ListArrayListString arrayList Collections.list(v.elements());print(ArrayListString arrayList Collections.list(v.elements()), arrayList: arrayList);} } /* list [one, Two, three, Four, five, six, one] Collections.disjoint(list, Collections.singletonList(Four)) false Collections.max(list) three Collections.min(list) Four Collections.max(list, String.CASE_INSENSITIVE_ORDER) Two Collections.min(list, String.CASE_INSENSITIVE_ORDER) five Arrays.asList(Four five six.split( )) [Four, five, six] Collections.indexOfSubList(list, sublist) 3 Collections.lastIndexOfSubList(list, sublist) 3 Collections.replaceAll(list, one, Yo), list [Yo, Two, three, Four, five, six, Yo] Collections.reverse(list), list [Yo, six, five, Four, three, Two, Yo] Collections.rotate(list, 3), list [three, Two, Yo, Yo, six, five, Four] Arrays.asList(in the matrix.split( )) source [in, the, matrix] Collections.copy(list, source), list [in, the, matrix, Yo, six, five, Four] Collections.swap(list, 0, list.size() - 1), list [Four, the, matrix, Yo, six, five, in] Collections.shuffle(list, new Random(47)), list [six, matrix, the, Four, Yo, five, in] Collections.fill(list, pop), list [pop, pop, pop, pop, pop, pop, pop] Collections.frequency(list, pop) 7 Collections.nCopies(3, snap) dups [snap, snap, snap] Collections.disjoint(list, dups) true Collections.disjoint(list, dups), list [pop, pop, pop, pop, pop, pop, pop] EnumerationString e Collections.enumeration(dups), e snap snap snap ArrayListString arrayList Collections.list(v.elements()), arrayList: [snap, snap, snap] */ 【17.11.1】List的排序和查找 1List排序和查找所使用的方法 与 对象数组所使用的相应方法 有相同的名字和语法只是用 Collections 的 static 代替 Arrays 的方法而已 // 荔枝-List的排序和查询 public class ListSortSearch {public static void main(String[] args) {// Utilities.list: static ListString list Arrays.asList(one Two three Four five six one.split( ));ListString list new ArrayListString(Utilities.list);list.addAll(Utilities.list);print(list list);// Collections.shuffle(list, new Random(47)) 随机改变list的元素顺序Collections.shuffle(list, new Random(47));print(Collections.shuffle(list, new Random(47)), list list);// Use a ListIterator to trim off the last elements:// 移除位置10包括0之后的元素ListIteratorString it list.listIterator(10);while (it.hasNext()) {it.next(); // 删除元素时先执行 next() 然后执行 remove()。 因为next()中, cursor i;cursor i1; return elementData[lastRet i]it.remove(); // remove() 方法中: 先 ArrayList.this.remove(lastRet), cursor lastRet,lastRet -1}print(Trimmed: list);// Collections.sort(list), list排序默认大小写敏感Collections.sort(list);print(Collections.sort(list); list list);String key list.get(7);// Collections.binarySearch(list, key), 通过二叉查找找出 元素key的位置默认大小写敏感int index Collections.binarySearch(list, key);print(Location of key is index , list.get( index ) list.get(index));// Collections.sort(list, String.CASE_INSENSITIVE_ORDER); list排序大小写不敏感Collections.sort(list, String.CASE_INSENSITIVE_ORDER);print(Collections.sort(list, String.CASE_INSENSITIVE_ORDER), list list);key list.get(7);// Collections.binarySearch(list, key), 通过二叉查找找出 元素key的位置大小写不敏感index Collections.binarySearch(list, key, String.CASE_INSENSITIVE_ORDER);print(Location of key is index , list.get( index ) list.get(index));} } /* list [one, Two, three, Four, five, six, one, one, Two, three, Four, five, six, one] Collections.shuffle(list, new Random(47)), list [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] Collections.sort(list); list [Four, Two, five, five, one, one, six, six, three, three] Location of six is 7, list.get(7) six Collections.sort(list, String.CASE_INSENSITIVE_ORDER), list [five, five, Four, one, one, six, six, three, three, Two] Location of three is 7, list.get(7) three */ // ArrrayList$Itr.next() remove() 方法源码public E next() {checkForComodification();int i cursor;if (i size)throw new NoSuchElementException();Object[] elementData ArrayList.this.elementData;if (i elementData.length)throw new ConcurrentModificationException();cursor i 1;return (E) elementData[lastRet i];}public void remove() {if (lastRet 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor lastRet;lastRet -1;expectedModCount modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}} 【17.11.2】设定Collection 或 Map 为不可修改创建只读容器 1荔枝-创建只读容器方法列表如下 // 荔枝-创建只读容器方法列表如下 /* Collections.unmodifiableCollection(new ArrayList()) Collections.unmodifiableList(new ArrayList()) Collections.unmodifiableSet(new HashSet()) Collections.unmodifiableSortedSet(new TreeSet()) // TreeSet 继承了 SortedSet Collections.unmodifiableMap(new HashMap()) Collections.unmodifiableSortedMap(new TreeMap()) // TreeMap 继承了 SortedMap */ public class ReadOnly {static CollectionString data new ArrayListString(Countries.names(6));public static void main(String[] args) {// Collections.unmodifiableCollection(new ArrayListString(data)), 创建只读的 ArrayListCollectionString c Collections.unmodifiableCollection(new ArrayListString(data));print(c); // Reading is OK// ! c.add(one); // Cant change it// Collections.unmodifiableList(new ArrayListString(data)), 创建只读的 ArrayListListString a Collections.unmodifiableList(new ArrayListString(data));ListIteratorString lit a.listIterator();print(lit.next()); // Reading is OK// ! lit.add(one); // Cant change it// Collections.unmodifiableSet(new HashSetString(data)) 创建只读的 HashSetSetString s Collections.unmodifiableSet(new HashSetString(data));print(s); // Reading is OK// ! s.add(one); // Cant change it// For a SortedSet: // Collections.unmodifiableSortedSet(new TreeSetString(data)), 创建只读的 TreeSetSetString ss Collections.unmodifiableSortedSet(new TreeSetString(data));print(SetString ss Collections.unmodifiableSortedSet(new TreeSetString(data)), ss ss);// Collections.unmodifiableMap() 创建只读的 HashMapMapString, String m Collections.unmodifiableMap(new HashMapString, String(Countries.capitals(6)));print(m); // Reading is OK// ! m.put(Ralph, Howdy!);// For a SortedMap:// Collections.unmodifiableSortedMap(),创建只读的TreeMapMapString, String sm Collections.unmodifiableSortedMap(new TreeMapString, String(Countries.capitals(6)));} } /* CollectionString c Collections.unmodifiableCollection(new ArrayListString(data)) c [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI] ALGERIA [BENIN, BOTSWANA, ANGOLA, BURKINA FASO, ALGERIA, BURUNDI] SetString ss Collections.unmodifiableSortedSet(new TreeSetString(data)), ss [ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI] {BENINPorto-Novo, BOTSWANAGaberone, ANGOLALuanda, BURKINA FASOOuagadougou, ALGERIAAlgiers, BURUNDIBujumbura} */ // Collections 创建不可修改容器的方法源码public static T CollectionT unmodifiableCollection(Collection? extends T c) {return new UnmodifiableCollection(c);}// Collection$UnmodifiableCollection.java 源码static class UnmodifiableCollectionE implements CollectionE, Serializable {private static final long serialVersionUID 1820017752578914078L;final Collection? extends E c;UnmodifiableCollection(Collection? extends E c) {if (cnull)throw new NullPointerException();this.c c;}public int size() {return c.size();}public boolean isEmpty() {return c.isEmpty();}public boolean contains(Object o) {return c.contains(o);}public Object[] toArray() {return c.toArray();}public T T[] toArray(T[] a) {return c.toArray(a);}public String toString() {return c.toString();}public IteratorE iterator() {return new IteratorE() {private final Iterator? extends E i c.iterator();public boolean hasNext() {return i.hasNext();}public E next() {return i.next();}public void remove() {throw new UnsupportedOperationException();}Overridepublic void forEachRemaining(Consumer? super E action) {// Use backing collection versioni.forEachRemaining(action);}};}public static T ListT unmodifiableList(List? extends T list) {return (list instanceof RandomAccess ?new UnmodifiableRandomAccessList(list) :new UnmodifiableList(list));}public static T SetT unmodifiableSet(Set? extends T s) {return new UnmodifiableSet(s);}public static T SortedSetT unmodifiableSortedSet(SortedSetT s) {return new UnmodifiableSortedSet(s);}public static K,V MapK,V unmodifiableMap(Map? extends K, ? extends V m) {return new UnmodifiableMap(m);}public static K,V SortedMapK,V unmodifiableSortedMap(SortedMapK, ? extends V m) {return new UnmodifiableSortedMap(m);} 【代码解说】对不可修改的容器调用 修改方法如新增或编辑编译器并不会报错但是任何改变容器内容的操作在执行时都会引起 UnsupportedOperationException 【17.11.3】 Collection 或 Map的同步控制 1Collections 类有办法自动同步整个容器 【干货】 Collections 有很多有用的工具方法如 通过Collections 创建不可修改的容器 和 自动同步整个容器 【荔枝-Collection 或 Map的同步机制, Colletions 自动同步整个容器的方法列表】 // 荔枝-Collection 或 Map的同步机制, Colletions 自动同步整个容器的方法列表 // Collections.synchronizedCollection(new ArrayList()) // Collections.synchronizedList(new ArrayList()) // Collections.synchronizedSet(new HashSetString()) // Collections.synchronizedMap(new HashMapString, String()) // Collections.synchronizedSortedMap(new TreeMapString, String()) public class Synchronization {public static void main(String[] args) {CollectionString c Collections.synchronizedCollection(new ArrayListString());ListString list Collections.synchronizedList(new ArrayListString());SetString s Collections.synchronizedSet(new HashSetString());SetString ss Collections.synchronizedSortedSet(new TreeSetString());MapString, String m Collections.synchronizedMap(new HashMapString, String());MapString, String sm Collections.synchronizedSortedMap(new TreeMapString, String());} } // /:~// Collections 自动同步整个容器的方法源码public static T CollectionT synchronizedCollection(CollectionT c) {return new SynchronizedCollection(c);}public static T ListT synchronizedList(ListT list) {return (list instanceof RandomAccess ?new SynchronizedRandomAccessList(list) :new SynchronizedList(list));}public static T SetT synchronizedSet(SetT s) {return new SynchronizedSet(s);}public static T SortedSetT synchronizedSortedSet(SortedSetT s) {return new SynchronizedSortedSet(s);}public static K,V MapK,V synchronizedMap(MapK,V m) {return new SynchronizedMap(m);}public static K,V SortedMapK,V synchronizedSortedMap(SortedMapK,V m) {return new SynchronizedSortedMap(m);}【java容器的快速报错机制】 1快速报错机制 java容器类类库采用了 快速报错机制。。该机制会探测容器上的任何除了你的进程操作外的所有变化一旦它发现其他进程修改了容器就会立刻抛出 ConcurrentModificationException异常。 2工作原理 只需创建一个 迭代器然后向迭代器所指向的 Collection添加 同步方法如下 【荔枝-java容器的快速报错机制】 // 荔枝-快速报错机制 public class FailFast {public static void main(String[] args) {CollectionString c new ArrayListString();IteratorString it c.iterator();c.add(An object);try {System.out.println(before it.next());String s it.next(); // it.next() 抛出异常System.out.println(after it.next());} catch (ConcurrentModificationException e) {System.out.println(e);}} } /* before it.next() java.util.ConcurrentModificationException */ 【代码解说】 it.next() 方法 抛出了异常。 因为程序部分1 在取得 容器的迭代器后 程序部分2 又向容器插入了元素。。当程序的不同部分修改同一个容器时就可能导致容器状态不一致所以java快速报错机制抛出了异常 这里抛出异常的原因是 获得迭代器后 迭代器的 int expectedModCount modCount; expectedModCount 被赋值 然后 c.add(An object); 又 把 mocCount 了。又迭代器的next() 方法 需要校验 expectedModCount 与 modCount 是否相等 显然 它们是不等的所以 next() 方法抛出异常 // ArrayList$Itr.java 源码荔枝 private class Itr implements IteratorE {int cursor; // index of next element to returnint lastRet -1; // index of last element returned; -1 if no suchint expectedModCount modCount;public boolean hasNext() {return cursor ! size;}SuppressWarnings(unchecked)public E next() {checkForComodification();int i cursor;if (i size)throw new NoSuchElementException();Object[] elementData ArrayList.this.elementData;if (i elementData.length)throw new ConcurrentModificationException();cursor i 1;return (E) elementData[lastRet i];} final void checkForComodification() {if (modCount ! expectedModCount)throw new ConcurrentModificationException();} // ... }【补充】 ConcurrentHashMap, CopyOnWriteArrayList 和 CopyOnWriteArraySet d都使用了可以避免 java.util.ConcurrentModificationException 的技术 【17.12】持有引用 1对象是可获得的如果一个对象是可获得的垃圾回收器不会释放它如果是不可获得的垃圾回收期回收它是安全的 2普通引用指的是没有经过 Reference 包装过的引用不会被垃圾回收器回收释放 3有3个类继承自 ReferenceSoftReference WeakReference PhantomReference 对应不同级别的可获得性由强到弱排列 3.1SoftReference实现内存敏感的高速缓存 3.2WeakReference实现规范映射而设计的不妨碍垃圾回收期回收 键值对 4使用 SoftReference 和 WeakReference 时可以选择是否要将它们放入 ReferenceQueue而 PhantomReference 仅仅依赖于 ReferencQueue 【荔枝】 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 ReferenceQueueVeryBig rq new ReferenceQueueVeryBig();public static void checkQueue() {Reference? extends VeryBig inq rq.poll();if (inq ! null)System.out.println(In queue: inq.get());}public static void main(String[] args) {int size 10;// Or, choose size via the command line:if (args.length 0)size new Integer(args[0]);LinkedListSoftReferenceVeryBig sa new LinkedListSoftReferenceVeryBig();for (int i 0; i size; i) {sa.add(new SoftReferenceVeryBig(new VeryBig(Soft i), rq));System.out.println(Just created: sa.getLast());checkQueue();}LinkedListWeakReferenceVeryBig wa new LinkedListWeakReferenceVeryBig();for (int i 0; i size; i) {wa.add(new WeakReferenceVeryBig(new VeryBig(Weak i), rq));System.out.println(Just created: wa.getLast());checkQueue();}SoftReferenceVeryBig s new SoftReferenceVeryBig(new VeryBig(Soft));WeakReferenceVeryBig w new WeakReferenceVeryBig(new VeryBig(Weak));System.gc();LinkedListPhantomReferenceVeryBig pa new LinkedListPhantomReferenceVeryBig();for (int i 0; i size; i) {pa.add(new PhantomReferenceVeryBig(new VeryBig(Phantom i),rq));System.out.println(Just created: pa.getLast());checkQueue();} } } /* Just created: java.lang.ref.SoftReference15db9742 Just created: java.lang.ref.SoftReference6d06d69c Just created: java.lang.ref.SoftReference7852e922 Just created: java.lang.ref.SoftReference4e25154f Just created: java.lang.ref.SoftReference70dea4e Just created: java.lang.ref.SoftReference5c647e05 Just created: java.lang.ref.SoftReference33909752 Just created: java.lang.ref.SoftReference55f96302 Just created: java.lang.ref.SoftReference3d4eac69 Just created: java.lang.ref.SoftReference42a57993 Just created: java.lang.ref.WeakReference75b84c92 Just created: java.lang.ref.WeakReference6bc7c054 Just created: java.lang.ref.WeakReference232204a1 Just created: java.lang.ref.WeakReference4aa298b7 Just created: java.lang.ref.WeakReference7d4991ad Just created: java.lang.ref.WeakReference28d93b30 Just created: java.lang.ref.WeakReference1b6d3586 Just created: java.lang.ref.WeakReference4554617c Just created: java.lang.ref.WeakReference74a14482 Just created: java.lang.ref.WeakReference1540e19d Finalizing Weak Finalizing Weak 9 Finalizing Weak 8 Finalizing Weak 7 Finalizing Weak 6 Finalizing Weak 5 Finalizing Weak 4 Finalizing Weak 3 Finalizing Weak 2 Finalizing Weak 1 Finalizing Weak 0 Just created: java.lang.ref.PhantomReference677327b6 In queue: null Just created: java.lang.ref.PhantomReference14ae5a5 In queue: null Just created: java.lang.ref.PhantomReference7f31245a In queue: null Just created: java.lang.ref.PhantomReference6d6f6e28 In queue: null Just created: java.lang.ref.PhantomReference135fbaa4 In queue: null Just created: java.lang.ref.PhantomReference45ee12a7 In queue: null Just created: java.lang.ref.PhantomReference330bedb4 In queue: null Just created: java.lang.ref.PhantomReference2503dbd3 In queue: null Just created: java.lang.ref.PhantomReference4b67cf4d In queue: null Just created: java.lang.ref.PhantomReference7ea987ac In queue: null */ 【17.12.1】 WeakHashMap 用来保存 WeakReference 1这是一种节约存储空间的技术 因为 WeakHashMap 允许垃圾回收器 自动清理键值对 【荔枝WeakHashMap 允许垃圾回收器 自动清理键值】 class Element {private String ident; // 缩进量public Element(String id) {ident id;}public String toString() {return ident;}// 重写 hashCode() 方法public int hashCode() {return ident.hashCode();}// 重写 equals() 方法public boolean equals(Object r) {return r instanceof Element ident.equals(((Element) r).ident);}protected void finalize() { // 垃圾回收时调用的方法System.out.println(Finalizing getClass().getSimpleName() ident);} }class Key extends Element {public Key(String id) {super(id);} }class Value extends Element {public Value(String id) {super(id);} }public class CanonicalMapping {public static void main(String[] args) {int size 1000;// Or, choose size via the command line:if (args.length 0)size new Integer(args[0]);Key[] keys new Key[size];// WeakHashMap 允许垃圾回收器 自动清理键值WeakHashMapKey, Value map new WeakHashMapKey, Value();for (int i 0; i size; i) {Key k new Key(Integer.toString(i));Value v new Value(Integer.toString(i));if (i % 3 0)keys[i] k; // 把序号为3的倍数的位置上的元素保存为真实引用map.put(k, v);}System.gc(); // 垃圾回收} } /* 可以看到垃圾回收器 仅仅回收 不存在 keys[] 数组中的对象因为不存在keys[] 数组该引用就不是真实引用是不可获得的引用可以回收 Finalizing Key 476 Finalizing Key 245 Finalizing Key 244 Finalizing Key 242 Finalizing Key 241 Finalizing Key 239 Finalizing Key 238 Finalizing Key 236 Finalizing Key 235 Finalizing Key 233 Finalizing Key 232 Finalizing Key 230 Finalizing Key 229 Finalizing Key 227 Finalizing Key 226 */ 【17.13】Java 1.0/1.1 容器 【17.13.1】 Vector 和 Enumeration 1Vector 可以看做是 ArrayList 2Enumeration迭代器 java 1.0/1.1 版本 发明了 枚举类 取代 迭代器Enumeration 是一个接口并不是一个实现类 【迭代器-Enumeration】 // Vector 和 Enumeration 的荔枝 public class Enumerations {public static void main(String[] args) {// Vector 相当于 ArrayList Vector 是 老式的 ArrayList不推荐 VectorVectorString v new VectorString(Countries.names(10));// Enumeration枚举类 相当于迭代器 Iterator Enumeration 是老式的 Iterator不推荐 EnumerationEnumerationString e v.elements(); // 生成 Enumeration 对象// Enumeration 的列表遍历方式while (e.hasMoreElements())System.out.print(e.nextElement() , );// Collections.enumeration(new ArrayListString()), 把 ArrayList的Iterator迭代器 转换为 Enumeration 枚举类e Collections.enumeration(new ArrayListString());} } /* Collections.enumeration() 方法源码 public static T EnumerationT enumeration(final CollectionT c) {return new EnumerationT() { // 静态内部类private final IteratorT i c.iterator();public boolean hasMoreElements() {return i.hasNext();}public T nextElement() {return i.next();}}; } */ /* ALGERIA, ANGOLA, BENIN, BOTSWANA, BURKINA FASO, BURUNDI, CAMEROON, CAPE VERDE, CENTRAL AFRICAN REPUBLIC, CHAD, */ 【17.13.2】 Hashtable 没有理由使用 Hashtable了使用 HashMap 替代 【17.13.3】Stack栈 栈可以通过 LinkedList 快速实现 1Stack 通过继承 Vector 来实现栈而不是 通过Vector 来构建 Stack 这是一个糟糕的设计永远不要使用 Stack public class StackE extends VectorE { // Stack 实现源码/*** Creates an empty Stack.*/public Stack() {} 【荔枝-实现栈的多种方式演示但绝不能使用 Stack 在生产过程中】 // 枚举类 enum Month {JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER } // 荔枝-实现栈的多种方式演示但绝不能使用 Stack 在生产过程中 public class Stacks {public static void main(String[] args) {// 第1种方式通过 StackStackString stack new StackString();for (Month m : Month.values())stack.push(m.toString()); // 进栈操作print(stack stack);// Treating a stack as a Vector:stack.addElement(The last line);print(element 5 stack.elementAt(5));print(popping elements:);while (!stack.empty())printnb(stack.pop() );// 第2种方式通过 LinkedListLinkedListString lstack new LinkedListString();for (Month m : Month.values())lstack.addFirst(m.toString());System.out.println();print(lstack lstack);while (!lstack.isEmpty())printnb(lstack.removeFirst() );// Using the Stack class from// the Holding Your Objects Chapter:// 第3种方式 通过 基于 LinkedList 的 Stack 来实现net.mindview.util.StackString stack2 new net.mindview.util.StackString();for (Month m : Month.values())stack2.push(m.toString());System.out.println();print(stack2 stack2);while (!stack2.empty())printnb(stack2.pop() );} } /* stack [JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER] element 5 JUNE popping elements: The last line NOVEMBER OCTOBER SEPTEMBER AUGUST JULY JUNE MAY APRIL MARCH FEBRUARY JANUARY lstack [NOVEMBER, OCTOBER, SEPTEMBER, AUGUST, JULY, JUNE, MAY, APRIL, MARCH, FEBRUARY, JANUARY] NOVEMBER OCTOBER SEPTEMBER AUGUST JULY JUNE MAY APRIL MARCH FEBRUARY JANUARY stack2 [NOVEMBER, OCTOBER, SEPTEMBER, AUGUST, JULY, JUNE, MAY, APRIL, MARCH, FEBRUARY, JANUARY] NOVEMBER OCTOBER SEPTEMBER AUGUST JULY JUNE MAY APRIL MARCH FEBRUARY JANUARY */【17.13.4】BitSet 1BitSet 最小容量是long64位可以高效率地存储大量 开关信息 2如果需要高效的访问时间 BitSet 比 本地数组稍慢一点 【荔枝-Bits 插入 和 数据演示】 // 荔枝-Bits 插入 和 数据演示 public class Bits {public static void printBitSet(BitSet b) {print(bits: b);StringBuilder bbits new StringBuilder();for (int j 0; j b.size(); j)bbits.append(b.get(j) ? 1 : 0);print(bit pattern: bbits);}public static void main(String[] args) {Random rand new Random(47);// Take the LSB of nextInt():byte bt (byte) rand.nextInt();BitSet bb new BitSet();for (int i 7; i 0; i--) // 每个byte 1个字节 8位所以需要8次位操作if (((1 i) bt) ! 0)bb.set(i);elsebb.clear(i);print(byte value: bt); // byte value: -107printBitSet(bb); // bits: {0, 2, 4, 7} bit pattern: 1010100100000000000000000000000000000000000000000000000000000000System.out.println();short st (short) rand.nextInt();BitSet bs new BitSet();for (int i 15; i 0; i--) // 每个short 2个字节 16位所以需要16次位操作if (((1 i) st) ! 0)bs.set(i);elsebs.clear(i);print(short value: st); //short value: 1302printBitSet(bs); //bits: {1, 2, 4, 8, 10} bit pattern: 0110100010100000000000000000000000000000000000000000000000000000System.out.println(); //int it rand.nextInt();BitSet bi new BitSet();for (int i 31; i 0; i--) // 每个 int 4个字节 32位if (((1 i) it) ! 0)bi.set(i);elsebi.clear(i);print(int value: it); // int value: -2014573909printBitSet(bi); // bits: {0, 1, 3, 5, 7, 9, 11, 18, 19, 21, 22, 23, 24, 25, 26, 31}// bit pattern: 1101010101010000001101111110000100000000000000000000000000000000System.out.println(); //// Test bitsets 64 bits:BitSet b127 new BitSet();b127.set(127); print(set bit 127: b127); // set bit 127: {127}BitSet b255 new BitSet(65);b255.set(255);print(set bit 255: b255); // set bit 255: {255}BitSet b1023 new BitSet(512);b1023.set(1023);b1023.set(1024);print(set bit 1023: b1023); // set bit 1023: {1023, 1024}} } /* byte value: -107 bits: {0, 2, 4, 7} bit pattern: 1010100100000000000000000000000000000000000000000000000000000000short value: 1302 bits: {1, 2, 4, 8, 10} bit pattern: 0110100010100000000000000000000000000000000000000000000000000000int value: -2014573909 bits: {0, 1, 3, 5, 7, 9, 11, 18, 19, 21, 22, 23, 24, 25, 26, 31} bit pattern: 1101010101010000001101111110000100000000000000000000000000000000set bit 127: {127} set bit 255: {255} set bit 1023: {1023, 1024} */3如何选择使用 BitSet 还是 EnumSet 3.1BitSet 只有在运行时才知道需要多少个标志 或标志命名不合理 或需要BitSet中的某种特殊操作 3.2EnumSet允许按照名字而不是数字位的位置进行操作可以减少错误 还可以防止你因不注意添加新的标志位置
http://www.huolong8.cn/news/446292/

相关文章:

  • 天河低价网站建设wordpress站
  • 建设百度网站wordpress vanilla
  • 做百度移动网站排名wordpress 免插件七牛
  • 旅游网站开发工具下列哪种是网页制作工具
  • 做项目搭建网站 构建数据库毕业设计做健身房网站的意义
  • 杭州软件开发培训学校对网站进行seo优化
  • 网站在国内服务器在国外网站制作 手机
  • 门诊部网站建设网络销售怎么做
  • 四川个人网站备案成都市微信网站建设报价
  • 如何做pdf电子书下载网站做网站购买域名之后
  • 网站如何运营建协的证书全国通用吗
  • 做数学题目在哪个网站好网站站外优化
  • idc机房托管费用seo优化方向
  • 宁波网站建设优化企业ios开发者账号续费
  • 免费的编程自学网站山西网络公司哪家专业
  • 简速做网站工作室网站使用mip后效果怎么样
  • 织梦免费网站模块下载地址学校门户网站建设工作
  • 大型门户网站建设服务花都网站开发
  • 狗和女人做的网站长沙网站建设哪个公司好
  • 备案图标怎么放在网站中3d演示中国空间站建造历程
  • 套模板的网站多少钱企业网站策划
  • 网站制作公司 佛山网站建设思维
  • 网站建设合同法东莞网站推广运营
  • 官网网站搭建需要多少钱设计网站的基本步骤
  • 中国建设银行网站登录不了怎么申请网址怎么用
  • 网站怎么制作陕西建设局网站
  • 常用网站建设工具自己做的网站买域名多少钱
  • 使用cnnic证书的网站茂名做网站的公司
  • 做网站的网站违不违法黄石有没有做网站的
  • 网站流量一直做不起来建设部网站示范文本