泛型,即“参数化类型”

1. 泛型只在编译阶段有效

2.不能对确切的泛型类型使用instanceof操作。如下面的操作是非法的,编译时会出错

if(ex_num instanceof Generic<Number>){   }

3.在集合和泛型的世界最好不要使用基本类型,尽量使用基本类的包装类,不易出现问题。
1、用泛型:
    List<T> list=newArrayList<T>(); 
    T t=list.get(0); 
2、不用泛型:
    List list=new ArrayList(); 
    T t=(T)list.get(0);

容器类应该算得上最具重用性的类库之一。先来看一个没有泛型的情况下的容器类如何定义: 

public class Container {private String key;private String value;public Container(String k, Stringv) {key = k;value = v;}
public String getKey() {return key;}public void setKey(String key) {this.key = key;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}
}

Container类保存了一对key-value键值对,但是类型是定死的,

也就说如果我想要创建一个键值对是String-Integer类型的,当前这个Container是做不到的,

必须再自定义。那么这明显重用性就非常低。

当然,我可以用Object来代替String,并且在JavaSE5之前,我们也只能这么做,

由于Object是所有类型的基类,所以可以直接转型。但是这样灵活性还是不够,

因为还是指定类型了,只不过这次指定的类型层级更高而已,有没有可能不指定类型?

有没有可能在运行时才知道具体的类型是什么?

所以,就出现了泛型。

public class Container<K,V> {private K key;private V value;public Container(K k, V v) {key = k;value = v;}public K getKey() {return key;}public void setKey(K key) {this.key = key;}public V getValue() {return value;}public void setValue(V value) {this.value = value;}
}

在编译期,是无法知道K和V具体是什么类型,只有在运行时才会真正根据类型来构造和分配内存。可以看一下现在Container类对于不同类型的支持情况:

public class Main {public static void main(String[] args) {Container<String, String> c1 =newContainer<String, String>("name", "findingsea");Container<String, Integer> c2 = newContainer<String, Integer>("age", 24);Container<Double, Double> c3 = newContainer<Double, Double>(1.1, 2.2);System.out.println(c1.getKey()+ " : " + c1.getValue());System.out.println(c2.getKey()+ " : " + c2.getValue());System.out.println(c3.getKey()+ " : " + c3.getValue());}
}

输出:

name : findingsea
age : 24
1.1 : 2.2

2、泛型接口

未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中

 * 即:class FruitGenerator<T> implements Generator<T>{

 * 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"

当实现泛型接口的类,传入泛型实参时

传入泛型实参时:

 * 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator<T>

 * 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。

 * 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型

 * 即:Generator<T>,public Tnext();中的的T都要替换成传入的String类型。

在泛型接口中,生成器是一个很好的理解,看如下的生成器接口定义:

public interfaceGenerator<T> {public T next();
}

然后定义一个生成器类来实现这个接口:

public class FruitGeneratorimplements Generator<String> {private String[] fruits =new String[]{"Apple", "Banana", "Pear"};public String next() {Random rand = new Random();returnfruits[rand.nextInt(3)];}
}

调用:

public class Main {public static void main(String[] args) {FruitGeneratorgenerator = new FruitGenerator();System.out.println(generator.next());System.out.println(generator.next());System.out.println(generator.next());System.out.println(generator.next());}
}

输出:

Banana

Banana

Pear

Banana

3、泛型方法

<T>放在修饰符合返值之间

 1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。

    2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。

   3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。

一个基本的原则是:无论何时,只要你能做到,你就应该尽量使用泛型方法。

也就是说,如果使用泛型

public class Main {public static <T> void out(T t) {System.out.println(t);}public static void main(String[] args) {out("findingsea");out(123);out(11.11);out(true);}
}

方法可以取代将整个类泛化,那么应该有限采用泛型方法。下面来看一个简单的泛型方法的定义:

可以看到方法的参数彻底泛化了,这个过程涉及到编译器的类型推导和自动打包,

也就说原来需要我们自己对类型进行的判断和处理,现在编译器帮我们做了。

这样在定义方法的时候不必考虑以后到底需要处理哪些类型的参数,大大增加了编程的灵活性。

 再看一个泛型方法和可变参数的例子:

public class Main {public static <T> void out(T... args) {for (T t : args) {System.out.println(t);}}public static void main(String[] args) {out("findingsea", 123, 11.11, true);}
}

输出和前一段代码相同,可以看到泛型可以和可变参数非常完美的结合。

关于泛型数组要提一下

看到了很多文章中都会提起泛型数组,经过查看sun的说明文档,在java中是”不能创建一个确切的泛型类型的数组”的。

也就是说下面的这个例子是不可以的:

List<String>[]ls = new ArrayList<String>[10]; 

而使用通配符创建泛型数组是可以的,如下面这个例子:

List<?>[]ls = new ArrayList<?>[10]; 

这样也是可以的:

List<String>[]ls = new ArrayList[10];

泛型通配符:

       当操作的不同容器中的类型都不确定的时候,而且使用的元素都是从Object类中继承的方法,这时泛型就用通配符“?”来表示。

泛型的通配符:“?”  相当于 “? extends Object

泛型限定:

        泛型限定就是对操作的数据类型限定在一个范围之内。限定分为上限和下限。

        上限:? extends E   接收E类型或E的子类型

        下限:? super E    接收E类型或E的父类型

        限定用法和泛型方法,泛型类用法一样,在“<>”中表达即可。

        一个类型变量或通配符可以有多个限定,多个限定用“&”分隔开,且限定中最多有一个类,可以有多个接口;如果有类限定,类限定必须放在限定列表的最前面。如:T extends MyClass1 & MyInterface1 & MyInterface2 

集合工具类Collections常用方法

1)public static <T> void sort(List<T> list):排序,默认情况下是自然顺序。

2)public static <T> int binarySearch(List<?> list,T key):二分查找,默认的是升序,其他顺序不能使用这个方法

3)public static <T> T max(Collection<?> coll):最大值

4)public static void reverse(List<?> list):反转

5)public static void shuffle(List<?> list):随机置换

生成一个中文按字典排序的比较器

public int compareTo(user o) {// TODO Auto-generated method stubCollator instance=Collator.getInstance(Locale.CHINA); return instance.compare(this.name, o.name); }

collections.sort

切记,排序的对象的成员类型必须是引用了

JAVA Collections工具类sort()排序方法

一、Collections工具类两种sort()方法

格式一: public static<T extends Comparable<? super T>>void sort(List<T> list)

说明:该方法中的泛型<T>都是Comparable接口的子类,即只有是Comparable接口子类类型的数据,才能进行比较排序。如果其他类型的数据要进行比较排序,必须继承Comparable接口并

覆写equals()和compareTo()方法。其中如String类、Integer类都是Comparable接口子类,可以进行排序,而基本类型不能进行sort排序。比较项目在类内指定

格式二:publicstatic <T> void sort(List<T> list,Comparator<? super T> c)

Comparator接口的两个方法

O1-O2升序

对于其结果,负数 表示降序,整数表示升序

 int

compare(T o1, T o2)
          比较用来排序的两个参数。比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数

 boolean

equals(Object obj)
          指示某个其他对象是否“等于”此 Comparator。

说明:该方法中指定比较方式Comparator<? super T> c,即c必须实现Comparator<? super T>接口,覆写compareTo()方法指定比较项目。比较项目在类外指定,比较灵活

首先使用基本类型(此处使用Integer)来演示第一个方法:

staticList<Integer> intList = Arrays.asList(2, 3, 1);
private stati cvoidsortBaseTypeByDefaultMode() {System.out.println("before sort:");PrintUtil.showList(intList);System.out.println("=========================");Collections.sort(intList);System.out.println("after sort:");PrintUtil.showList(intList);}

PrintUtil.showList是自定义的一个打印List类型的方法,此处只关心输出结果就行,如下:

可以看到,默认的排序是正序,那么如何实现逆序呢,这就要使用第二种方式了,即通过实现Comparator接口的compare方法来完成自定义排序,代码如下:  

  private static void sortBaseTypeByIDefineMode() {System.out.println("before sort:");PrintUtil.showList(intList);System.out.println("=========================");Collections.sort(intList,new Comparator<Integer>() {@Overridepublic int compare(Integer o1,Integer o2) {// 返回值为int类型,大于0表示正序,小于0表示逆序returno2-o1;}});System.out.println("after sort:");PrintUtil.showList(intList);}

ArrayList

注:Arraylist如果把一个元素删了,另一个元素会顶替他的位置,这点和数组不一样

所以选择排序去除重复的元素要j--。

ArrayList是一个动态数组,也是我们最常用的集合。它允许任何符合规则的元素插入甚至包括null。每一个ArrayList都有一个初始容量(10),该容量代表了数组的大小。随着容器中的元素不断增加,容器的大小也会随着增加。在每次向容器中增加元素的同时都会进行容量检查,当快溢出时,就会进行扩容操作。所以如果我们明确所插入元素的多少,最好指定一个初始容量值,避免过多的进行扩容操作而浪费时间、效率。

size、isEmpty、get、set、iterator 和 listIterator 操作都以固定时间运行。add操作以分摊的固定时间运行,也就是说,添加n 个元素需要 O(n) 时间(由于要考虑到扩容,所以这不只是添加元素会带来分摊固定时间开销那样简单)。

      ArrayList擅长于随机访问。同时ArrayList是非同步的。

LinkedList

同样实现List接口的LinkedList与ArrayList不同,ArrayList是一个动态数组,而LinkedList是一个双向链表。所以它除了有ArrayList的基本操作方法外还额外提供了get,remove,insert方法在LinkedList的首部或尾部。

由于实现的方式不同,LinkedList不能随机访问,它所有的操作都是要按照双重链表的需要执行。在列表中索引的操作将从开头或结尾遍历列表(从靠近指定索引的一端)。这样做的好处就是可以通过较低的代价在List中进行插入和删除操作。

与ArrayList一样,LinkedList也是非同步的。如果多个线程同时访问一个List,则必须自己实现访问同步。一种解决方法是在创建List时构造一个同步的List:
List list = Collections.synchronizedList(new LinkedList(…));

特有的方法

list.addFirst(1212);//LinkedList special method

list.addLast(88888);//LinkedList specialmethod

Vector

与ArrayList相似,但是Vector是同步的。所以说Vector是线程安全的动态数组。它的操作与ArrayList几乎一样。

Stack

Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop 方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。

Set接口

Set是一种不包括重复元素的Collection。它维持它自己的内部排序,所以随机访问没有任何意义。与List一样,它同样运行null的存在但是仅有一个。由于Set接口的特殊性,所有传入Set集合中的元素都必须不同,同时要注意任何可变对象,如果在对集合中元素进行操作时,导致e1.equals(e2)==true,则必定会产生某些问题。实现了Set接口的集合有:EnumSet、HashSet、TreeSet。

3.1、EnumSet

是枚举的专用Set。所有的元素都是枚举类型。

3.2、HashSet

HashSet堪称查询速度最快的集合,因为其内部是以HashCode来实现的。它内部元素的顺序是由哈希码来决定的,所以它不保证set 的迭代顺序;特别是它不保证该顺序恒久不变。

3.3、TreeSet与TreeMap

           基于TreeMap,生成一个总是处于排序状态的set,内部以红黑树实现。按照中序遍历,前、中、后三种顺序都可以有序的读取到集合中的元素它是使用元素的自然顺序对元素进行排序,或者根据创建Set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。

Map接口提供三个集合视图:

(1)Set keyset():返回map中包含的所有key的一个Set视图。集合是受map支持的,map的变化会在集合中反映出来,反之亦然。当一个迭代器正在遍历一个集合时,若map被修改了(除迭代器自身的移除操作以外),迭代器的结果会变为未定义。集合支持通过Iterator的Remove、Set.remove、removeAll、retainAll和clear操作进行元素移除,从map中移除对应的映射。它不支持add和addAll操作。

(2)Collection values():返回一个map中包含的所有value的一个Collection视图。这个collection受map支持的,map的变化会在collection中反映出来,反之亦然。当一个迭代器正在遍历一个collection时,若map被修改了(除迭代器自身的移除操作以外),迭代器的结果会变为未定义。集合支持通过Iterator的Remove、Set.remove、removeAll、retainAll和clear操作进行元素移除,从map中移除对应的映射。它不支持add和addAll操作。

(3)Set<Map.Entry<K,V>> entrySet():返回一个map钟包含的所有映射的一个集合视图。这个集合受map支持的,map的变化会在collection中反映出来,反之亦然。当一个迭代器正在遍历一个集合时,若map被修改了(除迭代器自身的移除操作,以及对迭代器返回的entry进行setValue外),迭代器的结果会变为未定义。集合支持通过Iterator的Remove、Set.remove、removeAll、retainAll和clear操作进行元素移除,从map中移除对应的映射。它不支持add和addAll操作。

3.4、Map接口

Map与List、Set接口不同,它是由一系列键值对组成的集合,提供了key到Value的映射。同时它也没有继承Collection。在Map中它保证了key与value之间的一一对应关系。也就是说一个key对应一个value,所以它不能存在相同的key值,当然value值可以相同。实现map的有:HashMap、TreeMap、HashTable、Properties、EnumMap。

4.1、HashMap

哈希表解决冲突的方法:通常有两类方法处理冲突:开放定址(Open Addressing)法和拉链(Chaining)法。前者是将所有结点均存放在散列表T[0..m-1]中;后者通常是将互为同义词的结点链成一个单链表,而将此链表的头指针放在散列表T[0..m-1]中。 

以哈希表数据结构实现,查找对象时通过哈希函数计算其位置,它是为快速查询而设计的,其内部定义了一个hash表数组(Entry[] table),元素会通过哈希转换函数将元素的哈希地址转换成数组中存放的索引,如果有冲突,则使用散列链表的形式将所有相同哈希地址的元素串起来,可通过查看HashMap.Entry的源码它是一个单链表结构。

4.2、TreeMap

键以某种排序规则排序,TreeMap元素默认从小到大排序内部以红黑树实现。按照中序遍历,前、中、后三种顺序都可以有序的读取到集合中的元素,实现了SortedMap接口

4.3、HashTable

也是以哈希表数据结构实现的,解决冲突时与HashMap也一样也是采用了散列链表的形式,不过性能比HashMap要低

五、Queue

队列,它主要分为两大类,一类是阻塞式队列,队列满了以后再插入元素则会抛出异常,主要包括ArrayBlockQueue、PriorityBlockingQueue、LinkedBlockingQueue。另一种队列则是双端队列,支持在头、尾两端插入和移除元素,主要包括:ArrayDeque、LinkedBlockingDeque、LinkedList。

4.4 Map.Entry

Map是java中的接口,Map.Entry是Map的一个内部接口。

Map提供了一些常用方法,如keySet()、entrySet()等方法。

keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。

Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry。它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。

4.5LinkedHashMap
LinkedHashMap也是一个HashMap,但是内部维持了一个双向链表,可以保持顺

异同点

出处:http://blog.csdn.net/softwave/article/details/4166598

6.1、Vector和ArrayList

1,vector是线程同步的,所以它也是线程安全的,而arraylist是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用arraylist效率比较高。
2,如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%.如过在集合中使用数据量比较大的数据,用vector有一定的优势。
3,如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,都是0(1),这个时候使用vector和arraylist都可以。而如果移动一个指定位置的数据花费的时间为0(n-i)n为总长度,这个时候就应该考虑到使用linklist,因为它移动一个指定位置的数据所花费的时间为0(1),而查询一个指定位置的数据时花费的时间为0(i)。

ArrayList和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,都允许直接序号索引元素,但是插入数据要设计到数组元素移动等内存操作,所以索引数据快插入数据慢,Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!

6.2、Aarraylist和Linkedlist

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。
2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
这一点要看实际情况的。若只对单条数据插入或删除,ArrayList的速度反而优于LinkedList。但若是批量随机的插入删除数据,LinkedList的速度大大优于ArrayList.因为ArrayList每插入一条数据,要移动插入点及之后的所有数据。

6.3、HashMap与TreeMap

1、HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。HashMap中元素的排列顺序是不固定的)。

3、在Map 中插入、删除和定位元素,HashMap是最好的选择。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。使用HashMap要求添加的键类明确定义了hashCode()和 equals()的实现。这个TreeMap没有调优选项,因为该树总处于平衡状态。

6.4、hashtable与hashmap

1、历史原因:Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现 。

2、同步性:Hashtable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的 。

3、值:只有HashMap可以让你将空值作为一个表的条目的key或value 。

对集合的选择

7.1、对List的选择

1、对于随机查询与迭代遍历操作,数组比所有的容器都要快。所以在随机访问中一般使用ArrayList

2、LinkedList使用双向链表对元素的增加和删除提供了非常好的支持,而ArrayList执行增加和删除元素需要进行元素位移。

3、对于Vector而已,我们一般都是避免使用。

4、将ArrayList当做首选,毕竟对于集合元素而已我们都是进行遍历,只有当程序的性能因为List的频繁插入和删除而降低时,再考虑LinkedList。

7.2、对Set的选择

1、HashSet由于使用HashCode实现,所以在某种程度上来说它的性能永远比TreeSet要好,尤其是进行增加和查找操作。

3、虽然TreeSet没有HashSet性能好,但是由于它可以维持元素的排序,所以它还是存在用武之地的。

7.3、对Map的选择

1、HashMap与HashSet同样,支持快速查询。虽然HashTable速度的速度也不慢,但是在HashMap面前还是稍微慢了些,所以HashMap在查询方面可以取代HashTable。

2、由于TreeMap需要维持内部元素的顺序,所以它通常要比HashMap和HashTable慢。

list和set主要区别

List保存的对象可以重复,元素有放入顺序,而Set不可以重复元素无放入顺序

(注意:元素虽然无放入顺序,但是元素在set中的位置是有该元素的HashCode决定的,其位置其实是固定的,加入Set 的Object必须定义equals()方法 ,另外list支持for循环,也就是通过下标来遍历,也可以用迭代器,但是set只能用迭代,因为他无序,无法用下标来取得想要的值。) 

.Set和List对比: 
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变。 

ArrayList与LinkedList的区别和适用场景

Arraylist:

优点:ArrayList是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询操作效率会比较高(在内存里是连着放的)。

缺点:因为地址连续, ArrayList要移动数据,所以插入和删除操作效率比较低。   

LinkedList:

优点:LinkedList基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,对于新增和删除操作add和remove,LinedList比较占优势。LinkedList 适用于要头尾操作或插入指定位置的场景

缺点:因为LinkedList要移动指针,所以查询操作性能比较低。

适用场景分析:

 当需要对数据进行对此访问的情况下选用ArrayList,当需要对数据进行多次增加删除修改时采用LinkedList。 

LinkedList和ArrayList是另个不同变量列表的实现。ArrayList的优势在于动态的增长数组,非常适合初始时总长度未知的情况下使用。LinkedList的优势在于在中间位置插入和删除操作,速度是最快的。

LinkedList实现了List接口,允许null元素。此外LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)

ArrayList和Vector都是用数组实现的,主要有这么三个区别:
1.Vector是多线程安全的,线程安全就是说多线程访问同一代码,不会产生不确定的结果。而ArrayList不是,这个可以从源码中看出,Vector类中的方法很多有synchronized进行修饰,这样就导致了Vector在效率上无法与ArrayList相比;

2.两个都是采用的线性连续空间存储元素,但是当空间不足的时候,两个类的增加方式是不同。

3.Vector可以设置增长因子,而ArrayList不可以。

4.Vector是一种老的动态数组,是线程同步的,效率很低,一般不赞成使用。

适用场景分析:

1.Vector是线程同步的,所以它也是线程安全的,而ArrayList是线程异步的,是不安全的。如果不考虑到线程的安全因素,一般用ArrayList效率比较高。
2.如果集合中的元素的数目大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector有一定的优势

 简单记忆线程安全的集合类: 喂!SHE! 喂是指  vector,S是指 stack,H是指  hashtable,E是指:Eenumeration

List中的certain()和set()都可以判断一个元素是否已经存在

Set常用方法:

set 的遍历 

1.迭代遍历: 

Set<String>set = new HashSet<String>();
Iterator<String>it = set.iterator();
while (it.hasNext()){ String str =it.next(); System.out.println(str);
} 

2.for循环遍历: 

for (String str : set){ System.out.println(str);
} 

add

boolean add(E e)(通过对比可知要看清API每个函数的类型和返回值)

如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。更确切地讲,如果此 set 没有包含满足 (e==null ? e2==null : e.equals(e2)) 的元素 e2,则向该 set 中添加指定的元素 e。如果此 set 已经包含该元素,则该调用不改变此 set 并返回false。结合构造方法上的限制,这就可以确保 set 永远不包含重复的元素。

size

int size()

返回 set 中的元素数(其容量)。如果 set 包含多个 Integer.MAX_VALUE 元素,则返回 Integer.MAX_VALUE

指定者:

接口 Collection<E> 中的 size

返回:

此 set 中的元素数(其容量)


isEmpty

boolean isEmpty()

如果 set 不包含元素,则返回 true

指定者:

接口 Collection<E> 中的 isEmpty

返回:

如果此 set 不包含元素,则返回 true


contains

boolean contains(Object o)

如果 set 包含指定的元素,则返回 true。更确切地讲,当且仅当 set 包含满足 (o==null ? e==null : o.equals(e)) 的元素 e 时返回 true

指定者:

接口 Collection<E> 中的 contains

参数:

o - 要测试此 set 中是否存在的元素

返回:

如果此 set 包含指定的元素,则返回 true

抛出:

ClassCastException - 如果指定元素的类型与此 set 不兼容(可选)

NullPointerException - 如果指定的元素为 null 并且此 set 不允许 null 元素(可选)


iterator

Iterator<E> iterator()

返回在此 set 中的元素上进行迭代的迭代器。返回的元素没有特定的顺序(除非此 set 是某个提供顺序保证的类的实例)。

指定者:

接口 Collection<E> 中的 iterator

指定者:

接口 Iterable<E> 中的 iterator

返回:

在此 set 中的元素上进行迭代的迭代器


toArray

Object[] toArray()

返回一个包含 set 中所有元素的数组。如果此 set 对其迭代器返回的元素的顺序作出了某些保证,那么此方法也必须按相同的顺序返回这些元素。

由于此 set 不维护对返回数组的任何引用,因而它是安全的。(换句话说,即使此 set 受到数组的支持,此方法也必须分配一个新的数组)。因此,调用者可以随意修改返回的数组。

此方法充当基于数组的 API 与基于 collection 的 API 之间的桥梁。

指定者:

接口 Collection<E> 中的 toArray

返回:

包含此 set 中所有元素的数组


toArray

<T> T[] toArray(T[] a)

返回一个包含此 set 中所有元素的数组;返回数组的运行时类型是指定数组的类型。如果指定的数组能容纳该 set,则它将在其中返回。否则,将分配一个具有指定数组的运行时类型和此 set 大小的新数组。

如果指定的数组能容纳此 set,并有剩余的空间(即该数组的元素比此 set 多),那么会将列表中紧接该 set 尾部的元素设置为 null。(只有在调用者知道此 set 不包含任何 null 元素时才能用此方法确定此 set 的长度)。

如果此 set 对其迭代器返回的元素的顺序作出了某些保证,那么此方法也必须按相同的顺序返回这些元素。

toArray() 方法一样,此方法充当基于数组的 API 与基于 collection 的 API 之间的桥梁。更进一步说,此方法允许对输出数组的运行时类型上进行精确控制,在某些情况下,可以用来节省分配开销。

假定 x 是只包含字符串的一个已知 set。以下代码用来将该 set 转储到一个新分配的 String 数组:

    String[] y = x.toArray(new String[0]);

注意,toArray(newObject[0]) toArray() 在功能上是相同的。

指定者:

接口 Collection<E> 中的 toArray

参数:

a - 存储此 set 中元素的数组(如果其足够大);否则将为此分配一个具有相同运行时类型的新数组。

返回:

包含此 set 中所有元素的数组

抛出:

ArrayStoreException - 如果指定数组的运行时类型不是此 set 中所有元素的运行时类型的超类型

NullPointerException - 如果指定的数组为 null


add

boolean add(E e)

如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。更确切地讲,如果此 set 没有包含满足 (e==null ? e2==null : e.equals(e2)) 的元素 e2,则向该 set 中添加指定的元素 e。如果此 set 已经包含该元素,则该调用不改变此 set 并返回 false。结合构造方法上的限制,这就可以确保 set 永远不包含重复的元素。

上述规定并未暗示 set 必须接受所有元素;set 可以拒绝添加任意特定的元素,包括 null,并抛出异常,这与 Collection.add 规范中所描述的一样。每个 set 实现应该明确地记录对其可能包含元素的所有限制。

指定者:

接口 Collection<E> 中的 add

参数:

e - 要添加到 set 中的元素

返回:

如果 set 尚未包含指定的元素,则返回 true

抛出:

UnsupportedOperationException - 如果此 set 不支持 add 操作

ClassCastException - 如果指定元素的类不允许它添加到此 set

NullPointerException - 如果指定的元素为 null 并且此 set 不允许 null 元素

IllegalArgumentException - 如果指定元素的某些属性不允许它添加到此 set


remove

boolean remove(Object o)

如果 set 中存在指定的元素,则将其移除(可选操作)。更确切地讲,如果此 set 中包含满足 (o==null ? e==null : o.equals(e)) 的元素 e,则移除它。如果此 set 包含指定的元素(或者此 set 由于调用而发生更改),则返回 true(一旦调用返回,则此 set 不再包含指定的元素)。

指定者:

接口 Collection<E> 中的 remove

参数:

o - 从 set 中移除的对象(如果存在)

返回:

如果此 set 包含指定的对象,则返回 true

抛出:

ClassCastException - 如果指定元素的类型与此 set 不兼容(可选)

NullPointerException - 如果指定的元素为 null,并且此 set 不允许 null 元素(可选)

UnsupportedOperationException - 如果此 set 不支持 remove 操作


containsAll

boolean containsAll(Collection<?> c)

如果此 set 包含指定 collection 的所有元素,则返回 true。如果指定的 collection 也是一个 set,那么当该 collection 是此 set 的子集 时返回 true

指定者:

接口 Collection<E> 中的 containsAll

参数:

c - 检查是否包含在此 set 中的 collection

返回:

如果此 set 包含指定 collection 中的所有元素,则返回 true

抛出:

ClassCastException - 如果指定 collection 中的一个或多个元素的类型与此 set 不兼容(可选)

NullPointerException - 如果指定的 collection 包含一个或多个 null 元素并且此 set 不允许 null 元素(可选),或者指定的 collection 为 null

另请参见:

contains(Object)


addAll

boolean addAll(Collection<? extends E> c)

如果 set 中没有指定 collection 中的所有元素,则将其添加到此 set 中(可选操作)。如果指定的 collection 也是一个 set,则 addAll 操作会实际修改此 set,这样其值是两个 set 的一个并集。如果操作正在进行的同时修改了指定的 collection,则此操作的行为是不确定的。

指定者:

接口 Collection<E> 中的 addAll

参数:

c - 包含要添加到此 set 中的元素的 collection

返回:

如果此 set 由于调用而发生更改,则返回 true

抛出:

UnsupportedOperationException - 如果 set 不支持 addAll 操作

ClassCastException - 如果某些指定 collection 元素的类不允许它添加到此 set

NullPointerException - 如果指定的 collection 包含一个或多个 null 元素并且此 set 不允许 null 元素,或者指定的 collection 为 null

IllegalArgumentException - 如果指定 collection 元素的某些属性不允许它添加到此 set

另请参见:

add(Object)


retainAll

boolean retainAll(Collection<?> c)

仅保留 set 中那些包含在指定 collection 中的元素(可选操作)。换句话说,移除此 set 中所有未包含在指定 collection 中的元素。如果指定的 collection 也是一个 set,则此操作会实际修改此 set,这样其值是两个 set 的一个交集

指定者:

接口 Collection<E> 中的 retainAll

参数:

c - 包含要保留到此 set 中的元素的 collection

返回:

如果此 set 由于调用而发生更改,则返回 true

抛出:

UnsupportedOperationException - 如果此 set 不支持 retainAll 操作

ClassCastException - 如果此 set 元素的类与指定的 collection 不兼容(可选)

NullPointerException - 如果此 set 包含 null 元素并且指定的 collection 不支持 null 元素(可选),或者指定的 collection 为 null

另请参见:

remove(Object)


removeAll

boolean removeAll(Collection<?> c)

移除 set 中那些包含在指定 collection 中的元素(可选操作)。如果指定的 collection 也是一个 set,则此操作会实际修改此 set,这样其值是两个 set 的一个不对称差集

指定者:

接口 Collection<E> 中的 removeAll

参数:

c - 包含要从此 set 中移除的元素的 collection

返回:

如果此 set 由于调用而发生更改,则返回 true

抛出:

UnsupportedOperationException - 如果此 set 不支持 removeAll 操作

ClassCastException - 如果此 set 元素的类与指定的 collection 不兼容(可选)

NullPointerException - 如果此 set 包含 null 元素并且指定的 collection 不允许 null 元素(可选),或者指定的 collection 为 null

另请参见:

remove(Object), contains(Object)


clear

void clear()

移除此 set 中的所有元素(可选操作)。此调用返回后该 set 将是空的。

指定者:

接口 Collection<E> 中的 clear

抛出:

UnsupportedOperationException - 如果此 set 不支持 clear 方法


equals

boolean equals(Object o)

比较指定对象与此 set 的相等性。如果指定的对象也是一个 set,两个 set 的大小相同,并且指定 set 的所有成员都包含在此 set 中(或者,此 set 的所有成员都包含在指定的 set 中也一样),则返回 true。此定义确保了 equals 方法可在不同的 set 接口实现间正常工作。

指定者:

接口 Collection<E> 中的 equals

覆盖:

Object 中的 equals

参数:

o - 要与此 set 进行相等性比较的对象

返回:

如果指定的对象等于此 set,则返回 true

另请参见:

Object.hashCode(), Hashtable


hashCode

int hashCode()

返回 set 的哈希码值。一个 set 的哈希码定义为此 set 中所有元素的哈希码和,其中 null 元素的哈希码定义为零。这就确保对于任意两个 set s1 s2 而言,s1.equals(s2) 就意味着 s1.hashCode()==s2.hashCode(),正如 Object.hashCode() 的常规协定所要求的那样。

指定者:

接口 Collection<E> 中的 hashCode

覆盖:

Object 中的 hashCode

返回:

此 set 的哈希码值

另请参见:

Object.equals(Object), equals(Object)

 

HashSet与Treeset的适用场景

1.TreeSet 是二差树(红黑树的树据结构)实现的,Treeset中的数据是自动排好序的,不允许放入null值

2.HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束 

3.HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例

  

   适用场景分析:HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。为快速查找而设计的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。

HashMap与TreeMap、HashTable的区别及适用场景

HashMap 非线程安全  

HashMap:基于哈希表实现。使用HashMap要求添加的键类明确定义了hashCode()和equals()[可以重写hashCode()和equals()],为了优化HashMap空间的使用,您可以调优初始容量和负载因子。 

 

TreeMap:非线程安全基于红黑树实现。TreeMap没有调优选项,因为该树总处于平衡状态。 

 

适用场景分析:

HashMap和HashTable:HashMap去掉了HashTable的contains方法,但是加上了containsValue()和containsKey()方法。HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。HashMap允许空键值,而HashTable不允许。

HashMap:适用于Map中插入、删除和定位元素。 

Treemap:适用于按自然顺序或自定义顺序遍历键(key)。                         

List<E>,Map<E>都是接口不能创建;

HashMap, HashTable, CurrentHashMap的区别

HashMapvs ConcurrentHashMap

引入ConcurrentHashMap是为了在同步集合HashTable之间有更好的选择,HashTableHashMapConcurrentHashMap主要的区别在于HashMap不是同步的、线程不安全的和不适合应用于多线程并发环境下,而ConcurrentHashMap是线程安全的集合容器,特别是在多线程和并发环境中,通常作为Map的主要实现。除了线程安全外,他们之间还有一些细微的不同,本文会介绍到。顺便说说,HashMapConcurrentHashMap还有ConcurrentHashMapHashtable两者之间的区别在Java面试中经常出现,特别是高级Java程序员。

HashMap与ConcurrentHashMap的区别

在这部分,我们会看到更多关于HashMapConcurrentHashMap的细节和对比它们之间的参数比如线程安全、同步、性能和基本的使用。

就像上面所说他们之间的第一个重要的区别就是ConcurrentHashMap是线程安全的和在并发环境下不需要加额外的同步。虽然它不像Hashtable那样需要同样的同步等级(全表锁),但也有很多实际的用途。

你可以使用Collections.synchronizedMap(HashMap)来包装HashMap作为同步容器,这时它的作用几乎与Hashtable一样,当每次对Map做修改操作的时候都会锁住这个Map对象,而ConcurrentHashMap会基于并发的等级来划分整个Map来达到线程安全,它只会锁操作的那一段数据而不是整个Map都上锁。

ConcurrentHashMap有很好的扩展性,在多线程环境下性能方面比做了同步的HashMap要好,但是在单线程环境下,HashMap会比ConcurrentHashMap好一点。

总结一下以上两者的区别,它们在线程安全、扩展性、同步之间的区别。如果是用于缓存的话,ConcurrentHashMap是一个更好的选择,在Java应用中会经常用到。ConcurrentHashMap在读操作线程数多于写操作线程数的情况下更胜一筹。

ConcurrentHashMapvs Hashtable vs Synchronized Map

虽然三个集合类在多线程并发应用中都是线程安全的,但是他们有一个重大的差别,就是他们各自实现线程安全的方式。Hashtable是jdk1的一个遗弃的类,它把所有方法都加上synchronized关键字来实现线程安全。所有的方法都同步这样造成多个线程访问效率特别低。SynchronizedMapHashTable差别不大,也是在并发中作类似的操作,两者的唯一区别就是SynchronizedMap没被遗弃,它可以通过使用Collections.synchronizedMap()来包装Map作为同步容器使用。

另一方面,ConcurrentHashMap的设计有点特别,表现在多个线程操作上。它不用做外的同步的情况下默认同时允许16个线程读和写这个Map容器。因为其内部的实现剥夺了锁,使它有很好的扩展性。不像HashTableSynchronizedMapConcurrentHashMap不需要锁整个Map,相反它划分了多个段(segments),要操作哪一段才上锁那段数据。

坦白说,集合类是一个最重要的Java API,我觉得恰当的使用它们是一种艺术。依我个人经验,我会使用ArrayList这些容器来提高自己的Java程序的性能,而不会去用一些遗弃的容器比如Vector等等,在Java 5之前,Java集合容器有一个很致命的缺陷就是缺乏可扩展性。
同步集合类比如
HashtableVector在多线程Java应用里面逐渐成为障碍物;在jdk5后出现一些很好的并发集合,对大容量、低延迟的电子交易系统有很大影响,是快速存取数据的支柱。

 

Hash家族

必须一次性两个值存储,就是所谓的键值对.

但是呢,Hash家族内部分为了几个小家族,分别是HashMap,Hashtable,TreeMap.

这几个家族呢,对键值对能不能存储null这种不是很安全的"买卖"有不一样的行动.

其中的HashMap家族与Hashtable、TreeMap不同,认为没有风险就没有利润!于是乎,准许自己的键值对都可以为null!

Hashtable与TreeMap一看SUN国王居然默许了HashMap的冒险行为,使得HashMap家族的利润大大增加,这两个家族也不甘寂寞,于是乎也就允许了自己的键值对可以为"",但是不能触碰null的界限.

Hashtable:

 1.key和value都不许有null值

 2.使用enumeration遍历

 3.同步的,每次只有一个线程能够访问

 4.在java中Hashtable是H大写,t小写,而HashMap是H大写,M大写

 

HashMap:

 1.key和value可以有null值

 2.使用iterator遍历

 3.未同步的,多线程场合要手动同步HashMap

 

 HashSet

 1.底层调用HashMap

 2.不允许有重复值

HashSet中是如何判断元素是否重复的

HashSet不能添加重复的元素,当调用add(Object)方法时候,
首先会调用Object的hashCode方法判hashCode是否已经存在,如不存在则直接插入元素;

如果已存在则调用Object对象的equals方法判断是否返回true,如果为true则说明元素已经存在,如为false则插入元素。

对添加元素的自定义要求

存入HashMap、HashSet的元素必须定义equals()方法和HashCode()方法,默认的HashCode()方法是Object的方法,其生成的散列码是使用对象的地址计算散列码,所以你new出来的两个类是具有不同的散列码的,尽管我们有时候希望当两个对象具有向相同的属性的时候,那么认为它们是同一个对象,这个时候就需要根据自己的需求重写HashCode()方法了,同时你还应该覆盖equals()方法,equals()方法会判断这个元素是否存在容器中,在前面有说到,而默认的equals()方法也是比较的元素的地址,我们可以按照自己的需求覆盖equals()方法。


正确的equals()方法必须满足下列5个条件:
1.自反性。对任意的x,x.equals(x) 一定返回true;
2.对称性。对任意的x和y, 如果x.equals(y)返回true, 则y.equals(x)一定返回true;
3.传递性。对任意x、y、z, 如果有x.equals(y)返回true,y.equals(z) 返回true,则x.equals(z)一定返回true;
4.一致性。对任意x和y,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false。
5.对任何不适null的x,x.equals(null)一定返回false。

在HashSet集合中添加三个Person对象,把姓名相同的人当做同一个人

思路:Person类中定义name和age属性,重写hashCode()方法和equals()方法,针对Person类的name属性进行比较,如果name相同,hashCode()方法的返回值相同,equals方法返回true。
当然利用系统给出的重现equals和hashcode已经和地下一样重写了

public class Person {  

    private String name;  

    private int age;  

    public Person(String name,int age)  

    {  

        this.name=name;  

        this.age=age;  

    }  

      

    @Override  

    public int hashCode() {  

        final int prime = 31;  

        int result = 1;  

        result = prime * result + ((name == null) ? 0 : name.hashCode());  

        return result;  

//31是一个素数,当然也可以用其它的,只是一个默认的传统,用31*1+hashcode是因为jvm虚拟机可以对结果值做优化,至于优化的具体实现都是虚拟机完成的,这个只要遵循即可

// name.hashCode()则是将name值转换为hash值,再加上前面的固定值,这样就造成了,如果name值在不被修改的情况下,return result返回的永远是一个固定值,这样就判定了是否一致

    }  

  

    @Override  

    public boolean equals(Object obj) {  

        if (this == obj)  

            return true;  

        if (obj == null)  

            return false;  

        if (getClass() != obj.getClass())  

            return false;  

        Person other = (Person) obj;  

        if (name == null) {  

            if (other.name != null)  

                return false;  

        } else if (!name.equals(other.name))  

            return false;  

        return true;  

    }  

 

为何Map接口不继承Collection接口?

尽管Map接口和它的实现也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map继承Collection毫无意义,反之亦然。

如果Map继承Collection接口,那么元素去哪儿?Map包含key-value对,它提供抽取key或value列表集合的方法,但是它不适合“一组对象”规范。

Map常用方法

Map的k可以重复但是value使用最新的
Map接口中有两个重要的数据结构,一个是keySetp,用Set集合保存了所有key;一个是内部类Entry,用来封装key-value对,每个元素对应一个Entry对象,保存在Map的全局数组transientEntry table[];中。

Map是键值对集合

HashTable和 HashMap 是 Map 的实现类

HashTable是线程安全的,不能存储 null 值

HashMap不是线程安全的,可以存储 null 值

 

put

public V put(K key, V value)

将指定的值与此映射中的指定键关联(可选操作)。如果此映射以前包含一个该键的映射关系,则用指定值替换旧值(当且仅当m.containsKey(k)返回true时,才能说映射m包含键k的映射关系)。返回之前的value

get

public V get(Object key)

返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null

remove

public V remove(Object key)

如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。更确切地讲,如果此映射包含从满足 (key==null ?k==null :key.equals(k)) 的键 k 到值 v 的映射关系,则移除该映射关系。(该映射最多只能包含一个这样的映射关系。)

返回此映射中以前关联该键的值,如果此映射不包含该键的映射关系,则返回 null

.底层实现:

     1. ArrayList:底层实现是数组

    2.Vectory:Vector提供synchronized修饰方法,是线程安全版本的ArrayList,故底层实现也是数组

     3.LinkedList:链式存储的线性表,实质是双向链表。实现了List和Deque接口。Deque代表双端队列,既可以当做队列也可以当作栈。

5.      TreeMap和TreeSet:

TreeSet的底层是用TreeMap实现的
     TreeMap底层是用红黑树来存储,每个Entry对应树的一个节点,TreeMap元素默认从小到大排序。V put(Key k, Value v)实质是二叉排序树的插入算法

通过观察TreeSet的底层源码发现,TreeSet的add(E e)方法,底层是根据实现Comparable的方式来实现的唯一性,通过compare(Object o)的返回值是否为0来判断是否为同一元素。
compare() == 0,元素不入集合。
compare() > 0 ,元素入右子树。
compare() < 0,元素入左子树。
而对其数据结构:自平衡二叉树做前(常用)、中、后序遍历即可保证TreeSet的有序性。

     5.HashMap和Hashtable和HashSet:
        HashMap和Hashtable和Hashset底层是用数组+链表存储的,元素是Entry。向HashMap添加<Key,Value>时,由key的hashcode决定Entry存储位置,当两个Entry对象的key的hashcode相同时,由   key的equals()方法返回值决定采用覆盖行为(返回true),还是在链表头添加新的Entry(返回false)。Collection<V> values(),返回集合对象,但不能添加元素,主要是用来遍历。

HashSet

HashSet由哈希表(实际上是一个HashMap实例)支持,不保证set的迭代顺序,并允许使用null元素。

基于HashMap实现,API也是对HashMap的行为进行了封装,可参考HashMap

LinkedHashMap实现原理

 

LinkedHashMap继承于HashMap,底层使用哈希表和双向链表来保存所有元素,并且它是非同步,允许使用null值和null键。

基本操作与父类HashMap相似,通过重写HashMap相关方法,重新定义了数组中保存的元素Entry,来实现自己的链接列表特性。该Entry除了保存当前对象的引用外,还保存了其上一个元素before和下一个元素after的引用,从而构成了双向链接列表。

LinkedHashSet实现原理要点概括

  1. 对于LinkedHashSet而言,它继承与HashSet、又基于LinkedHashMap来实现的。LinkedHashSet底层使用LinkedHashMap来保存所有元素,它继承与HashSet,其所有的方法操作上又与HashSet相同。

 

各集合特点(重复,线程安全)

 1.线程安全分类:

     线程安全的有:vector,hashtable,StringBuffer    

      线程不安全的有:ArrayList,hashmap,hashset,TreeSet,TreeMap

 2.元素可重复性

 Set < E > 是一个不包含重复元素的 集合。set 不包含满足 e1.equals(e2) 的元素对 e1 和 e2,并且最多包含一个 null 元素。
 故:HashSet < E > 和 TreeSet < E >不允许元素重合

List集合去除重复数据的方法:

1. 循环list中的所有元素然后删除重复

public   static   List  removeDuplicate(Listlist)  {       
  for  ( int  i  =   0 ; i  < list.size()  -   1 ; i ++ ) {       
      for  ( int  j  = list.size()  -   1 ; j  >  i; j -- ) {       
           if (list.get(j).equals(list.get(i)))  {       
             list.remove(j);       
           }        
       }        
      }        
    return list;       
}

2. 通过HashSet踢除重复元素

public static List removeDuplicate(List list) {   
HashSet h = new HashSet(list);   
list.clear();   
list.addAll(h);   
return list;   
}

3. 删除ArrayList中重复元素,保持顺序

public static void removeDuplicateWithOrder(List list) {   
    Set set = new HashSet();    
     List newList = new ArrayList();    
   for (Iterator iter = list.iterator(); iter.hasNext();){    
         Object element =iter.next();    
         if(set.add(element))    
           newList.add(element);    
      }     
     list.clear();    
     list.addAll(newList);    
    System.out.println( " remove duplicate " +list);    
 }   
4.把list里的对象遍历一遍,用list.contain(),如果不存在就放入到另外一个list集合中

public static List removeDuplicate(Listlist){  
        List listTemp = new ArrayList(); 
        for(int i=0;i<list.size();i++){ 
           if(!listTemp.contains(list.get(i))){  
               listTemp.add(list.get(i));  
            }  
        }  
        return listTemp;  
    }  
3.是否可以储存空值null
HashSet / HashMap / ArrayList / LinkedList均可接受null值

而TreeSet就不允许出现null 

集合之间的相互转化

1. List-->数组

  切记转成的数组是Object类型的数组

List<String> list = new ArrayList<String>();  

list.add("蹇伟");  

list.add("Jerval");  

list.add("杰威");  

Object[] objects = list.toArray();//返回Object数组  

System.out.println("objects:"+Arrays.toString(objects));  

String[] strings1 = new String[list.size()];  

list.toArray(strings1);//将转化后的数组放入已经创建好的对象中  

System.out.println("strings1:"+Arrays.toString(strings1));  

String[] strings2 = list.toArray(new String[0]);//将转化后的数组赋给新对象  

System.out.println("strings2:"+Arrays.toString(strings2));  

2.数组-->List  此时的数组必须是引用类型,比如整形的,必须是Integer[]

String[] ss = {"JJ","KK"};  

List<String> list1 = Arrays.asList(ss);  

List<String> list2 = Arrays.asList("AAA","BBB");  

System.out.println(list1);  

System.out.println(list2);  

3.List-->Set

List<String> list3 = new ArrayList<String>(new HashSet<String>());   

4.Set-->List

Set<String> set = new HashSet<String>(new ArrayList<String>());  

5.数组-->Set

String[] strs = {"AA","BB"};  

Set<String> set2 = new HashSet<String>(Arrays.asList(strs));  

System.out.println(set2);  

6.Set-->数组

Set<String> set3 = new HashSet<String>(Arrays.asList("PP","OO"));  

String[] strSet = new String[set3.size()];  

set3.toArray(strSet);  

System.out.println(Arrays.toString(strSet));  

7.Map操作

//使用entrySet来实现HashMap转化为Set

Set<Map.Entry<Student,String>> s=map.entrySet();集合

此时Set里面储存的是一个条目 Entry

Map<String, String> map = new HashMap<String, String>();  

map.put("YYY", "UUU");  

map.put("RRR", "TTT");  

// 将键转化为Set

Set<String> mapKeySet = map.keySet();  

// 将值转化为Set

Set<String> mapValuesSet = new HashSet<String>(map.values());  

// 将值转化为List

List<String> mapValuesList = new ArrayList<String>(map.values());  

·   

集合遍历

Iterator和ListIterator的区别

 

●ListIterator有add()方法,可以向List中添加对象,而Iterator不能。

●ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator就不可以。

 

●ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。

●都可实现删除对象,但是ListIterator可以实现对象的修改,set()方法可以实现。Iierator仅能遍历,不能修改。

 

遍历List集合的三种方法

List<String>list = new ArrayList<String>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
方法一:
超级for循环遍历
for(String attribute : list) {
  System.out.println(attribute);
}
方法二:
对于ArrayList来说速度比较快, 用for循环, 以size为条件遍历:
for(int i = 0 ; i < list.size() ; i++) {
  system.out.println(list.get(i));
}
方法三:
集合类的通用遍历方式, 从很早的版本就有, 用迭代器迭代
Iterator it = list.iterator();
while(it.hasNext()) {
  System.ou.println(it.next);
}

对 set 的遍历

1.迭代遍历: 

Set<String>set = new HashSet<String>(); 

Iterator<String>it = set.iterator(); 

while (it.hasNext()) { 

  String str = it.next(); 

  System.out.println(str); 

2.for循环遍历: 

for (String str : set) { 

      System.out.println(str); 

优点还体现在泛型 假如 set中存放的是Object

Set<Object>set = new HashSet<Object>(); 

for循环遍历: 

for (Object obj: set) { 

      if(obj instanceof Integer){ 

                intaa= (Integer)obj; 

             }elseif(obj instanceofString){ 

               String aa = (String)obj 

             } 

Arraylist遍历

//遍历方式1  

Iterator<String> it1 = al.iterator();  

while(it1.hasNext()){  

System.out.println(it1.next());  

}  

        

//遍历方式2  

for(Iterator it2 = al.iterator();it2.hasNext();){  

System.out.println(it2.next());  

}  

        

//遍历方式3  

for(String temp:al){  

System.out.println(temp);  

}  

      

//遍历方式4  

for(int i = 0;i<al.size();i++){  

System.out.println(al.get(i));  

}  

Map遍历

1.使用Map.Entry遍历:推荐,尤其是容量大时

Map<String,ArrayList<String>> map = new HashMap<>();

for(Map.Entry<String, ArrayList<String>> entry : map.entrySet()) {

     String key = entry.getKey();

     ArrayList<String> item =entry.getValue();

 

2. 通过Map.keySet获得key在遍历key和value
里面有两种遍历方式

 for-each 循环遍历keys和values

Set<Integer>  set=map.keySet();

                   for (Integer ob:set) {

                            System.out.println("key: "+ob+"value: "+map.get(ob));

 使用Iterator

Iterator<Integer>it=set.iterator();

while(it.hasNext()){

Integeri=it.next();

System.out.println("键"+i+"值"+map.get(i));

3通过Map.values()遍历所有的value,但不能遍历key

注意用Collection来接受value

Collection<String>set1=map.values();

                   for (String str:set1) {

                            System.out.println(str);

                   }

集合的嵌套

HashMap嵌套HashMap

[java] view plain copy

<span style="font-size:18px;">    /* 

     * HashMap嵌套HashMap 

     *  

     * 传智播客 

     *      jc  基础班 

     *              陈玉楼     20 

     *              高跃      22 

     *      jy  就业班 

     *              李杰      21 

     *              曹石磊     23 

     *  

     * 先存储元素,然后遍历元素 

     */  

    public void test3(){  

          

        // 创建集合对象  

        HashMap<String, HashMap<String, Integer>> czbkMap = new HashMap<String, HashMap<String, Integer>>();  

  

        // 创建基础班集合对象  

        HashMap<String, Integer> jcMap = new HashMap<String, Integer>();  

        // 添加元素  

        jcMap.put("陈玉楼", 20);  

        jcMap.put("高跃", 22);  

        // 把基础班添加到大集合  

        czbkMap.put("jc", jcMap);  

  

        // 创建就业班集合对象  

        HashMap<String, Integer> jyMap = new HashMap<String, Integer>();  

        // 添加元素  

        jyMap.put("李杰", 21);  

        jyMap.put("曹石磊", 23);  

        // 把基础班添加到大集合  

        czbkMap.put("jy", jyMap);  

          

        //遍历集合  

        Set<String> czbkMapSet = czbkMap.keySet();  

        for(String czbkMapKey : czbkMapSet){  

            System.out.println(czbkMapKey);  

            HashMap<String, Integer> czbkMapValue = czbkMap.get(czbkMapKey);  

            Set<String> czbkMapValueSet = czbkMapValue.keySet();  

            for(String czbkMapValueKey : czbkMapValueSet){  

                Integer czbkMapValueValue = czbkMapValue.get(czbkMapValueKey);  

                System.out.println("\t"+czbkMapValueKey+"---"+czbkMapValueValue);  

            }  

        }  

          

    }</span>  

 

HashMap集合的值是ArrayList

[java] view plain copy

<span style="font-size:18px;">    /* 

     *需求: 

     *假设HashMap集合的元素是ArrayList。有3个。 

     *每一个ArrayList集合的值是字符串。 

     *元素我已经完成,请遍历。 

     *结果: 

     *       三国演义 

     *          吕布 

     *          周瑜 

     *       笑傲江湖 

     *          令狐冲 

     *          林平之 

     *       神雕侠侣 

     *          郭靖 

     *          杨过   

     */  

    public void test4(){  

        // 创建集合对象  

        HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();  

  

        // 创建元素集合1  

        ArrayList<String> array1 = new ArrayList<String>();  

        array1.add("吕布");  

        array1.add("周瑜");  

        hm.put("三国演义", array1);  

  

        // 创建元素集合2  

        ArrayList<String> array2 = new ArrayList<String>();  

        array2.add("令狐冲");  

        array2.add("林平之");  

        hm.put("笑傲江湖", array2);  

  

        // 创建元素集合3  

        ArrayList<String> array3 = new ArrayList<String>();  

        array3.add("郭靖");  

        array3.add("杨过");  

        hm.put("神雕侠侣", array3);  

          

        //遍历集合  

        Set<String> set = hm.keySet();  

        for(String key : set){  

            System.out.println(key);  

            ArrayList<String> value = hm.get(key);  

            for(String s : value){  

                System.out.println("\t"+s);  

            }  

        }  

    }</span>  

ArrayList集合嵌套HashMap

[java] view plain copy

<span style="font-size:18px;">    /* 

     ArrayList集合嵌套HashMap集合并遍历。 

     需求: 

     假设ArrayList集合的元素是HashMap。有3个。 

     每一个HashMap集合的键和值都是字符串。 

     元素我已经完成,请遍历。 

     结果: 

     周瑜---小乔 

     吕布---貂蝉 

 

     郭靖---黄蓉 

     杨过---小龙女 

 

     令狐冲---任盈盈 

     林平之---岳灵珊 

     */  

    public void test5(){  

          

        // 创建集合对象  

        ArrayList<HashMap<String, String>> array = new ArrayList<HashMap<String, String>>();  

  

        // 创建元素1  

        HashMap<String, String> hm1 = new HashMap<String, String>();  

        hm1.put("周瑜", "小乔");  

        hm1.put("吕布", "貂蝉");  

        // 把元素添加到array里面  

        array.add(hm1);  

  

        // 创建元素1  

        HashMap<String, String> hm2 = new HashMap<String, String>();  

        hm2.put("郭靖", "黄蓉");  

        hm2.put("杨过", "小龙女");  

        // 把元素添加到array里面  

        array.add(hm2);  

  

        // 创建元素1  

        HashMap<String, String> hm3 = new HashMap<String, String>();  

        hm3.put("令狐冲", "任盈盈");  

        hm3.put("林平之", "岳灵珊");  

        // 把元素添加到array里面  

        array.add(hm3);  

  

        // 遍历  

        for (HashMap<String, String> hm : array) {  

            Set<String> set = hm.keySet();  

            for (String key : set) {  

                String value = hm.get(key);  

                System.out.println(key + "---" + value);  

            }  

        }  

    }  

    </span>  

多层嵌套

[java] view plain copy

<span style="font-size:18px;">    /* 

     * 为了更符合要求: 

     *      这次的数据就看成是学生对象。 

     *  

     * 学校 

     *      bj  北京校区 

     *          jc  基础班 

     *                  林青霞     27 

     *                  风清扬     30 

     *          jy  就业班  

     *                  赵雅芝     28 

     *                  武鑫      29 

     *      sh  上海校区 

     *          jc  基础班 

     *                  郭美美     20 

     *                  犀利哥     22 

     *          jy  就业班  

     *                  罗玉凤     21 

     *                  马征      23 

     *      gz  广州校区 

     *          jc  基础班 

     *                  王力宏     30 

     *                  李静磊     32 

     *          jy  就业班  

     *                  郎朗      31 

     *                  柳岩      33 

     *      xa  西安校区 

     *          jc  基础班 

     *                  范冰冰     27 

     *                  刘意      30 

     *          jy  就业班  

     *                  李冰冰     28 

     *                  张志豪     29 

     */  

    public void test6(){  

          

        // 创建大集合  

        HashMap<String, HashMap<String, ArrayList<Student>>> czbkMap = new HashMap<String, HashMap<String, ArrayList<Student>>>();  

  

        // 北京校区数据  

        HashMap<String, ArrayList<Student>> bjCzbkMap = new HashMap<String, ArrayList<Student>>();  

        ArrayList<Student> array1 = new ArrayList<Student>();  

        Student s1 = new Student("林青霞", 27);  

        Student s2 = new Student("风清扬", 30);  

        array1.add(s1);  

        array1.add(s2);  

        ArrayList<Student> array2 = new ArrayList<Student>();  

        Student s3 = new Student("赵雅芝", 28);  

        Student s4 = new Student("武鑫", 29);  

        array2.add(s3);  

        array2.add(s4);  

        bjCzbkMap.put("基础班", array1);  

        bjCzbkMap.put("就业班", array2);  

        czbkMap.put("北京校区", bjCzbkMap);  

  

        // 晚上可以自己练习一下  

        // 上海校区数据自己做  

        // 广州校区数据自己做  

  

        // 西安校区数据  

        HashMap<String, ArrayList<Student>> xaCzbkMap = new HashMap<String, ArrayList<Student>>();  

        ArrayList<Student> array3 = new ArrayList<Student>();  

        Student s5 = new Student("范冰冰", 27);  

        Student s6 = new Student("刘意", 30);  

        array3.add(s5);  

        array3.add(s6);  

        ArrayList<Student> array4 = new ArrayList<Student>();  

        Student s7 = new Student("李冰冰", 28);  

        Student s8 = new Student("张志豪", 29);  

        array4.add(s7);  

        array4.add(s8);  

        xaCzbkMap.put("基础班", array3);  

        xaCzbkMap.put("就业班", array4);  

        czbkMap.put("西安校区", xaCzbkMap);  

  

        // 遍历集合  

        Set<String> czbkMapSet = czbkMap.keySet();  

        for (String czbkMapKey : czbkMapSet) {  

            System.out.println(czbkMapKey);  

            HashMap<String, ArrayList<Student>> czbkMapValue = czbkMap  

                    .get(czbkMapKey);  

            Set<String> czbkMapValueSet = czbkMapValue.keySet();  

            for (String czbkMapValueKey : czbkMapValueSet) {  

                System.out.println("\t" + czbkMapValueKey);  

                ArrayList<Student> czbkMapValueValue = czbkMapValue  

                        .get(czbkMapValueKey);  

                for (Student s : czbkMapValueValue) {  

                    System.out.println("\t\t" + s.getName() + "---"  

                            + s.getAge());  

                }  

            }  

        }  

}</span>  

REMOVE操作在for循环的误用

错误1:循环遍历

<span style="font-size:14px;">for(int i=0;i<list.size();i++){

if(list.get(i).equals("del"))

list.remove(i);

}</span>

这种方式的问题在于,删除某个元素后,list的大小发生了变化,而你的索引也在变化,所以会导致你在遍历的时候漏掉某些元素。比如当你删除第1个元素后,继续根据索引访问第2个元素时,因为删除的关系后面的元素都往前移动了一位,所以实际访问的是第3个元素。因此,这种方式可以用在删除特定的一个元素时使用,但不适合循环删除多个元素时使用.

2)错误2:增强for循环

<span style="font-size:14px;">for(String x:list){

if(x.equals("del"))

list.remove(x);

}</span>

这种方式的问题在于,删除元素后继续循环会报错误信息ConcurrentModificationException,因为元素在使用的时候发生了并发的修改,导致异常抛出。但是删除完毕马上使用break跳出,则不会触发报错。

java集合终极总结相关推荐

  1. java 集合 接口_Java集合之Collection接口

    1 - Java集合介绍 /* 1. 一方面, 面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象 的操作,就要对对象进行存储. 2. 另一方面,使用Array存储对象方面具有一些弊 端,而 ...

  2. java 头尾 队列_超详细的java集合讲解

    1 集合 1.1 为什么会出现集合框架 [1] 之前的数组作为容器时,不能自动拓容 [2] 数值在进行添加和删除操作时,需要开发者自己实现添加和删除. 1.2 Collection接口 1.2.1 C ...

  3. java集合总结_Java中集合总结

    Java数组的长度是固定的,为了使程序能够方便地存储和操作数目不固定的一组数据,JDK类库提供了Java集合,这些集合类都位于java.util包中,但是与数组不同的是,集合中不能存放基本类型数据,而 ...

  4. 考考基础部分,谈谈Java集合中HashSet的原理及常用方法

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:工匠初心 cnblogs.com/LiaHon/p/1125 ...

  5. Java集合框架综述,这篇让你吃透!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:平凡希 cnblogs.com/xiaoxi/p/60899 ...

  6. 【Java集合框架】ArrayList类方法简明解析(举例说明)

    本文目录 1.API与Java集合框架 2.ArrayList类方法解析 2.1 add() 2.2 addAll() 2.3 clear() 2.4 clone() 2.5 contains() 2 ...

  7. Java基础篇:Java集合

    文章目录 1.概述 2.Collection接口 2.1 Collection接口方法 2.2 Iterator迭代器接口 2.3 Collection子接口之:List接口 2.4 Collecti ...

  8. java奇怪的问题_一个奇怪的Java集合问题

    int size = list.size(); Integer existIndex = -1; for (int index = 0; index < size; index++) { Pho ...

  9. Java集合框架的知识总结(1)

    Java集合框架的知识总结(1) 所有集合类都位于java.util包下.集合中只能保存对象(保存对象的引用变量). Java的集合类主要由两个接口派生而出:Collection和Map,Collec ...

  10. java集合框架史上最详解(list set 以及map)

    title: Java集合框架史上最详解(list set 以及map) tags: 集合框架 list set map 文章目录 一.集合框架总体架构 1.1 集合框架在被设计时需满足的目标 1.2 ...

最新文章

  1. 【lombok】使用lombok注解,在代码编写过程中可以调用到get/set方法,但是在编译的时候无法通过,提示找不到get/set方法...
  2. Spring Cloud Stream如何消费自己生产的消息?
  3. (2.4)备份与还原--WAL与备份原理
  4. TabControl控件
  5. 域名状态:运营商设置了客户禁止删除保护?过期域名也不能注册为什么?
  6. php poi,GitHub - satthi/poi-php: poi-php
  7. 数据库数据类型和占用字节数对比
  8. 浏览器静态资源的缓存机制(http强缓存 协商缓存)
  9. 神舟刷蓝天w650dbios_Hasse神舟笔记本卡logo解决,刷BIOS方法,教你修复神船
  10. 成都市计算机会考,四川省高中信息技术会考资料及试题
  11. Redis 过期策略和内存淘汰机制
  12. 如何汉化eclipse
  13. 【笔记】python中的for循环(遍历列表)、for循环中的一些缩进问题
  14. 和风天气API调用结果乱码
  15. 网络通过猫传输到计算机,网络直接从光猫出来好还是接个路由器再接入电脑好?看完搞懂了...
  16. OPC UA - Open62541学习
  17. MIMIC数据库权限申请
  18. java.lang.ClassNotFoundException:org.springframework.transaction.TransactionException
  19. 看大数据平台如何打造餐饮业务一体化?
  20. 英伟达 gsync demo NVIDIA 钟摆测试

热门文章

  1. 抽基类与PullToRefreshListView
  2. 一生必看的经典电影(转载)
  3. 固定table首行或尾行
  4. python syntax error_python提示Syntax Error报错解决教程
  5. 电脑linux 开启热点hostapt,Ubuntu16.04开启热点
  6. 在web服务器上运行html文件,再调用cgi打开txt文件
  7. python 004 __小斌文档 | 判断和循环
  8. 魔方还原算法(一) 概述
  9. 利用c++深究周立功usbcan盒的学习
  10. mysql8只有ibd文件_只有ibd文件还能恢复数据吗