您好,欢迎访问一九零五行业门户网

Java之集合概述

一、集合概述
java中有好多集合:list,arraylist,vector,hashsettreeset,它们之间的区别,java集合的框架等等总是很模糊,称有时间总结下。
     当数据多了需要存储,需要容器,而数据的个数不确定,无法使用数组,这时可以使用java中另一个容器——集合,位于java.util 。 
    1、集合和数组的区别?
   ① 数组的长度是固定的。
       集合的长度是可变的。
   ②数组中存储的是同一类型的元素,可以存储基本数据类型值。
      集合存储的都是对象。而且对象的类型可以不一致。
    2、什么时候使用集合呢?
        当对象多的时候,先进行存储。 
   3、集合体系框架图
二、collection接口
      collection接口:单列集合类的根接口
1、list接口:有序的,带索引的,通过索引就可以精确的操作集合中的元素,允许出现重复的元素。
                 使用list解决插入元素的问题,因为add方法追加。
                 list接口的特有方法,全部是围绕索引来定义的。
                 list获取元素的方式有两种:一种是迭代,一种是遍历+get方法。
                 list接口是支持对元素进行curd增删改查动作的。
①vector:可以增长的数组结构。同步的。效率非常低,已被arraylist替代。
   ②arraylist:是数组结构,长度是可变的(原理创建新数组+复制数组),查询速度很快,增删较慢,不同步的。(应用广)。
  示例:
 1 public class example01 {  2     public static void main(string[] args) {  3         arraylist list = new arraylist();  //创建arraylist集合  4         list.add(stu1);  5         list.add(stu2);  6         list.add(stu3);  7         list.add(stu4);  8         system.out.println(集合的长度:+list.size());//获得集合中元素的个数  9         system.out.println(集合的第二个元素:+list.get(1));//取出并打印指定位置的元素 10     } 11 }
运行结果:
集合的长度:4集合的第二个元素:stu2
③linktedlist:是链接结构,增删速度快,查询速度慢。可用于实现堆栈,队列。特有:围绕头和为展开定义的。
   堆栈:先进后出first in last out filo 可以理解为手枪弹夹
   队列:先进先出first in first out filo 可以理解为排队买票
   常用方法示例:
 1 public class example02 {  2     public static void main(string[] args) {  3         linkedlist link = new linkedlist();//创建linkedlist集合  4         link.add(stu1);  5         link.add(stu2);  6         link.add(stu3);  7         link.add(stu4);  8         system.out.println(link.tostring());//取出元素并打印该集合中的元素  9         link.add(3,student); //向该集合中的指定位置插入元素 10         link.addfirst(first);           //向该集合第一个位置插入元素 11         link.addlast(last);             //向该集合第一个位置插入元素 12         system.out.println(link); 13         system.out.println(link.getfirst()); //取出该集合第一个元素 14         system.out.println(link.getlast()); //取出该集合最后一个个元素 15         link.remove(3);                //移除该集合中指定位置的元素 16         link.removefirst();                  //移除该集合中第一个元素 17         link.removelast();                  //移除该集合中最后一个个元素 18         system.out.println(link); 19     } 20 }
运行结果:
[stu1, stu2, stu3, stu4] [first, stu1, stu2, stu3, student, stu4, last] first last [stu1, stu2, student, stu4]
2、iterator接口
     集合的取出方式:
①创建集合对象
       collection coll = new arraylist();
     ②获取容器的迭代器对象,通过iterator方法;
       iterator it = coll.iterator();
      ③使用具体的迭代器对象获取集合中的元素;
while (it.hasnext()){     system.out.println(it.next()); }
实际开发建议使用以下方法(随着迭代完成,迭代器随之变成垃圾被清除,可以减少所占内存):
for(iterator it = coll.iterator();it.hasnext();){      system.out.println(it.next()); }
该迭代器无法再迭代的过程中修改数组元素,否则会发生并发修改异常(concurrentmodificationexception)。
3、foreach:
    其实就是增强for循环,用于遍历collection和数组通常只能遍历元素,不要在遍历的过程中做对集合元素的操作。
格式:
for(元素数据类型 变量 :collection集合or数组()){执行语句}
和老式for循环的区别?
注意:新for循环必须有被遍历的目标。目标只能是collection或者是数组。
建议:遍历数组时,如果仅为遍历,可以使用增强for,如果要对数组的元素进行操作,使用老式for循环可以通过角标操作。
   示例:
 1 public class foreach {  2     static string [] strs = {aaa,bbb,ccc};  3     public static void main(string[] args) {  4         //foreach循环遍历数组  5         for(object obj : strs){  6             system.out.println(obj);  7         }  8             system.out.println(______________);  9         //foreach循环遍历数组并修改(修改失败) 10         for (string str : strs){ 11             str=ddd; 12         } 13         system.out.println(foreach循环修改后的数组:+strs[0]+,+strs[1]+,+strs[2]); 14         //for循环遍历数组 15         for(int i = 0;i<strs.length;i++){ 16 strs[i]="ddd"; 17 } 18 system.out.println("普通for循环修改后的数组:"+strs[0]+","+strs[1]+","+strs[2]); 19 } 20 }
运行结果:
1 aaa 2 bbb 3 ccc 4 ______________ 5 foreach循环修改后的数组:aaa,bbb,ccc 6 普通for循环修改后的数组:ddd,ddd,ddd
4、listiterator迭代器
iterator的子类,该列表迭代只有list接口有,而且这个迭代器可以完成在迭代过程中的增删改查动作。
add方法示例:
1 public class adddemo { 2 public static void main(string[] args) { 3 4 //在最前面添加 5 list<string> list1 = new linkedlist<string>(arrays.aslist(  6                 new string[] { a, b, c }));  7         listiterator<string> listiterator1 = list1.listiterator();  8         listiterator1.add(d);  9         listiterator1.add(e); 10         system.out.println(list1);//[d, e, a, b, c] 11         //在最后面添加 12         list<string> list2 = new linkedlist<string>(arrays.aslist( 13                 new string[] { a, b, c })); 14         listiterator<string> listiterator2 = list2.listiterator(); 15         while (listiterator2.hasnext()) { 16             listiterator2.next(); 17         } 18         listiterator2.add(d); 19         listiterator2.add(e); 20         system.out.println(list2);//[a, b, c, d, e] 21         //在每个元素的前面和后面都添加 22         list<string> list3 = new linkedlist<string>(arrays.aslist( 23                 new string[] { a, b, c })); 24         listiterator<string> listiterator3 = list3.listiterator(); 25         while (listiterator3.hasnext()) { 26             listiterator3.add(前面); 27             listiterator3.next(); 28             listiterator3.add(后面); 29         } 30         system.out.println(list3);//[前面, a, 后面, 前面, b, 后面, 前面, c, 后面] 31         //在指定元素的前面和后面添加 32         list<string> list4 = new linkedlist<string>(arrays.aslist( 33                 new string[] { a, b, c })); 34         listiterator<string> listiterator4 = list4.listiterator(); 35         while (listiterator4.hasnext()) { 36             if (listiterator4.next().equals(a)) {//现在指向的是a的后面 37                 listiterator4.previous();//先重新指向a的前面,这里不用担心nosuchelementexception 38                 listiterator4.add(前面);//在前面添加元素,添加后还是指向的a的前面 39                 listiterator4.next();//向后【再】移动一位,现在指向的是a的后面 40                 listiterator4.add(后面);//在a的后面添加元素 41             } 42         } 43         system.out.println(list4);//[前面, a, 后面, b, c]  44     } 45 }
remove方法示例:
 1 public class removedemo {  2     public static void main(string[] args) {  3   4 // 执行next()或previous()后不能先执行了 add()方法。  5 // 因为add()方法执行以后,迭代器已经移动了,这样所要删除的目标元素指向不明,会报异常。  6         //标准的做法:在next之后才能remove  7         list<string> list2 = new linkedlist<string>(arrays.aslist(  8                 new string[] { b, a, b, c, b, }));  9         listiterator<string> listiterator2 = list2.listiterator(); 10         while (listiterator2.hasnext()) { 11             if (listiterator2.next().equals(b)) {listiterator2.remove();} 12         } 13         system.out.println(list2);//[a, c] 14  15         //移除指定范围内的所有元素 16         list<string> list3 = new linkedlist<string>(arrays.aslist( 17                 new string[] { a, 开始, b, c, d, 结束, e })); 18         listiterator<string> listiterator3 = list3.listiterator(); 19         while (listiterator3.hasnext()) { 20             if (listiterator3.next().equals(开始)) { 21                 listiterator3.remove();//注释掉这行代码则不移除开始 22                 while (listiterator3.hasnext()) { 23                     if (!listiterator3.next().equals(结束)) { 24                         listiterator3.remove();//remove之后必须再调用next方法后才能再remove 25                     } else { 26                         listiterator3.remove();//注释掉这行代码则不移除结束 27                         break;//结束while循环 28                     } 29                 } 30             } 31         } 32         system.out.println(list3);//[a, e] 33         //替换指定元素 34         list<string> list5 = new linkedlist<string>(arrays.aslist( 35                 new string[] { a, b, c })); 36         listiterator<string> listiterator5 = list5.listiterator(); 37         while (listiterator5.hasnext()) { 38             if (listiterator5.next().equals(b)) { 39                 listiterator5.remove(); 40                 listiterator5.add(替换); 41             } 42         } 43         system.out.println(list5);//[a, 替换, c] 44     } 45 }
5、set接口
     不包含重复元素的集合,不保证顺序。而且方法和collection一致。set集合取出元素的方式只有一种:迭代器。
     ①hashset:哈希表结构,不同步,保证元素唯一性的方式依赖于: hashcode(),equals()方法。查询速度快。哈希值是根据存储位置来计算。
 1 class student{  2     private string id;  3     private string name;  4     public student(string id,string name){  5         this.id = id;  6         this.name = name;  7     }  8 //    重写tostring方法  9     public string tostring(){ 10         return id+:+name; 11     } 12 //    重写hashcode方法 13     public int hashcode(){ 14         return id.hashcode();//返回id属性的哈希值 15     } 16 //    重写equals方法 17     public boolean equals(object obj){ 18         if(this==obj){                  //判断是否为同一个对象 19             return true;                 //如果是,直接返回true 20         } 21         if (!(obj instanceof student)){   //判断对象是否student类型 22             return false;                 //如果对象不是student类型,返回false 23         } 24         student stu = (student)obj;        //将对象强转为student类型 25         boolean b= this.id.equals(stu.id); //判断id值是否相同 26         return b;                           //返回判断结果 27     } 28 } 29 public class hashsetdemo { 30     public static void main(string[] args) { 31         hashset set = new hashset(); 32         student stu1= new student(1,jack); 33         student stu2= new student(2,rose); 34         student stu3= new student(2,rose); 35         set.add(stu1); 36         set.add(stu2); 37         set.add(stu3); 38         system.out.println(set); 39     } 40 }
运行结果:
[1:jack, 2:rose] 若不重写hashcode()和equals()方法,则输出结果是: [2:rose,1:jack, 2:rose]
②treeset:可以对set集合中的元素进行排序。使用的是二叉树结构。如何保证元素唯一性的?使用的是对象比较方法的结果是否为0,是0,视为相同元素不存。
        元素的排序比较有两种方式:
元素自身具备自然排序,其实就是实现了comparable接口重写compareto方法。如果元素自身不具备自然排序,或具备的自然排序不是所需要的,这时只能用第二种方式。
比较器,其实就是在创建treeset集合时,在构造函数中指定具体的比较方式。需要定义一个类实现comparator接口,重写compare方法。
 1 class student implements comparable{  //定义student类实现comparable接口  2     string name;  3     int age;  4     public student(string name,int age){   //创建构造方法  5         this.name = name;  6         this.age = age;  7     }  8     public string tostring(){    //重写object类tostring()方法,返回描述信息  9         return name+:+age; 10     } 11     public int compareto(object obj){  //重写comparable接口compareto方法 12         student s =(student) obj;   //将比较对象强转为student类型 13         if (this.age -s.age>0){       //定义比较方法 14             return 1; 15         } 16         if (this.age-s.age==0){ 17             return this.name.compareto(s.name);//将比较结果返回 18         } 19         return -1; 20     } 21 } 22 public class treesetdemo { 23     public static void main(string[] args) { 24         treeset ts = new treeset(); 25         ts.add(new student(jack,19)); 26         ts.add(new student(rose,18)); 27         ts.add(new student(tom,19)); 28         ts.add(new student(rose,18)); 29         iterator it = ts.iterator(); 30         while (it.hasnext()){ 31             system.out.println(it.next()); 32         } 33     } 34 } 运行结果: rose:18 jack:19 tom:19
到此为止:在往集合中存储对象时,通常该对象都需要覆盖hashcode,equals,同时实现comparable接口,建立对象的自然排序。通常还有一个方法也会复写tostring();
 三、map接口:
      双列集合map集合的特点:内部存储的都是键key值value对,必须要保证键的唯一性。
      map集合常用方法
①hashtable---数据结构:哈希表。是同步的,不允许null作为键和值。被hashmap替代。
   子类properties:属性表,键和值都是字符串,而且可以结合流进行键值操作。唯一一个可以和io流结合使用的集合类。
②hashmap---数据结构:哈希表。不是同步的,允许null作为键和值。
示例:
 1 public class example15 {  2     public static void main(string[] args){  3       map map = new hashmap();      //创建map对象  4       map.put(1,jack);     //存储键和值,键相同,值覆盖  5       map.put(2,rose);  6       map.put(3,lucy);  7       map.put(3,mary);  8       system.out.println(1:+map.get(1));//根据键获取值  9       system.out.println(2:+map.get(2)); 10       system.out.println(3:+map.get(3)); 11     } 12 }
map集合的两种遍历方式:
 1 public class example16 {  2     public static void main(string[] args){  3         //第一种先遍历map集合中所有的键,再跟据键获取相应的值。  4         map map1 = new hashmap();      //创建map对象  5         map1.put(1,jack);     //存储键和值  6         map1.put(2,rose);  7         map1.put(3,lucy);  8         set keyset1 = map1.keyset();          //获取键的集合  9         iterator it1 = keyset1.iterator();     10         while (keyset1.iterator().hasnext()){  // 迭代键的集合 11             object key = it1.next(); 12             object value = map1.get(key);      //获得每个键所对应的值 13             system.out.println(key+:+value); 14         } 15          16         //第二种先获取集合中的所有映射关系,然后从映射关系中取出键和值 17         map map2 = new hashmap(); 18         map2.put(1,jack);     //存储键和值 19         map2.put(2,rose); 20         map2.put(3,lucy); 21         set entryset = map2.entryset(); 22         iterator it = entryset.iterator();    //获取iterator对象 23         while (it.hasnext()){ 24             map.entry entry = (map.entry)(it.next()); //获取集合中键值对映射关系 25             object key = entry.getkey();      //获取entry中的键 26             object value = entry.getvalue();  //获取entry中的值 27             system.out.println(key+:+value); 28         } 29     } 30 }
运行结果:
1:jack 2:rose 3:lucy
linkedhashmap:基于链表+哈希表。可以保证map集合有序(存入和取出的顺序一致)。
③treemap---数据结构:二叉树,保证键的唯一性,同步的,可以对map集合中的键进行排序。
 1 //按学号从大排到小  2 public class example20 {  3     public static void main(string[] args) {  4         treemap tm = new treemap(new mycompartor());  //传入一个自定义比较器  5         tm.put(1,jack);     //存储键和值  6         tm.put(2,rose);  7         tm.put(3,lucy);  8         set keyset = tm.keyset();          //获取键的集合  9         iterator it = keyset.iterator();    // 迭代键的集合 10         while (it.hasnext()){ 11             object key = it.next(); 12             object value = tm.get(key);      //获得每个键所对应的值 13             system.out.println(key+:+value); 14         } 15     } 16 } 17 class mycompartor implements comparator{   //自定义比较器 18     public int compare(object o1, object o2) {  //实现比较方法 19         string id1 = (string) o1;      //将object类型的参数强转为string类型 20         string id2 = (string) o2;         21         return id2.compareto(id1);     //将比较结果之后的值返回,按字典相反顺序进行排序 22     } 23 }
运行结果:
3:lucy 2:rose 1:jack
四、 泛型(parameterized type)
     1、泛型的使用
      体现<数据类型>,<>也是括号,往括号里写都写其实就是在传递参数。
       格式:arraylist<参数化类型> list = new arraylist<参数化类型>();
      泛型的优点:安全机制;将运行时期的classcastexecption转移到了编译时期变成了编译失败。泛型技术,是给编译器使用的技术。避免了强转的麻烦。
    示例: 1 public class example23 {  2     public static void main(string[] args) {  3         arraylist<string> list = new arraylist<string>();  4         list.add(string);  5         list.add(collection);  6         for(string str:list){  7             system.out.println(str);  8         }  9     } 10 }
2、自定义泛型:
需求:请自己提供一个容器类。
分析:你要做一个容器类,你就应该知道容器类具备什么基本功能?
添加功能 save()
获取功能 get()
要做这样的方法,save是不是应该有参数呢?肯定的。
get()应该有参数吗?这里我们可以不给形式参数,但是一定要有返回值类型。
基本格式:
void save (参数类型 参数){…}
返回值类型 get(){…..}
为了让我们的容器类能够存储任意类型的对象,我就应该给save()方法中的参数定义为object类型。
当然,get()方法的返回值类型应该是object类型。
出现问题:a 不兼容类型 b 类型转换异常
需求:自己定义一个泛型类并使用
如何定义一个泛型类呢?
就是把泛型安装其格式加在类上。
格式:
<参数化类型>可以是e、t这样有意义的单词。
使用泛型后,我们可以不用再做类型转换了。
//在创建类时,声明参数类型为t class 类名<t>{        t temp; //在创建save()方法时,指定参数类型为t        public void save (t temp){this.temp = temp} //在创建get()方法时,指定返回值类型为t        public t get(){               return temp;         } }
示例:
 1 class cachepool<t>{  2     t temp;  3     public void save(t temp){  4         this.temp=temp;  5     }  6     public t get() {  7         return temp;  8     }  9 } 10 public class example26 { 11     public static void main(string[] args) { 12         cachepool<integer> pool = new cachepool<integer>(); 13         pool.save(new integer(1)); 14         integer temp = pool.get(); 15         system.out.println(temp); 16     } 17 }
五、collections工具类
collections:集合框架中的用于操作集合对象工具类。都是静态方法。
获取collection最值。
对list集合排序,也可以用二分查找。
对排序逆序。
可以将非同步的集合转变成同步的集合。如:xxx synchronizedxxx(xxx) -------list synchronizedlist (list)
 //排序操作  1 public class example27 {  2     public static void main(string[] args) {  3     arraylist list = new arraylist();  4     collections.addall(list,c,z,b,k);  5     system.out.println(排序前:+list);  6     collections.reverse(list);  7     system.out.println(反转后:+list);  8     collections.shuffle(list);  9     system.out.println(按自然顺序排序后:+list); 10     collections.sort(list); 11     system.out.println(洗牌后:+list); 12     } 13 }
运行结果:
排序前:[c, z, b, k] 反转后:[k, b, z, c] 按自然顺序排序后:[c, b, k, z] 洗牌后:[b, k, c, z]

//查找、替换操作
1 public class example28 {  2     public static void main(string[] args) {  3         arraylist list = new arraylist();  4         collections.addall(list,-3,2,9,5,8);  5         system.out.println(集合中的元素:+list);  6         system.out.println(集合中的最大元素:+collections.max(list));  7         system.out.println(集合中的最小元素:+collections.min(list));  8         collections.replaceall(list,8,0);  //将集合中的8用0替换掉  9         system.out.println(替换后的集合:+list); 10     } 11 }
运行结果:
集合中的元素:[-3, 2, 9, 5, 8] 集合中的最大元素:9集合中的最小元素:-3替换后的集合:[-3, 2, 9, 5, 0]
六、arrays:用于操作数组的工具类。类中定义的都是静态工具方法。
对数组排序。
二分查找。
数组复制。
对两个数组进行元素的比较,判断两个数组是否相同。
将数组转成字符串。
 1 //使用arrays的sort()方法排序  2 public class example29 {  3     public static void main(string[] args) {  4         int[] arr={9,8,3,5,2};  5         system.out.print(排序前:);  6         printarray(arr);  7         arrays.sort(arr);  8         system.out.print(排序后:);  9         printarray(arr); 10     } 11     public static void printarray(int[] arr) { 12         system.out.print([); 13         for (int x=0;x 排序前:[9,8,3,5,2]
排序后:[2,3,5,8,9]
1 //使用arrays的binarysearch(object[] a,object key)方法查找元素 2 class example { 3     public void run() { 4         int[] arr={9,8,3,5,2}; 5         arrays.sort(arr);//调用排序方法,对数组排序 6         int index = arrays.binarysearch(arr,3);//查找指定元素3 7         system.out.println(数组排序后元素3的索引是:+index);//输出打印元素所在的索引位置 8     } 9 } 数组排序后元素3的索引是:1
1 //使用arrays的copyofrange(int[] original,int from,int to)方法拷贝元素  2 class example31 {  3     public void run() {  4         int[] arr={9,8,3,5,2};  5         int[] copies=arrays.copyofrange(arr,1,7);  6         for (int i =0;i 1 //使用arrays的fill(object[] a,object val)方法填充元素  2 class example{  3     public void run() {  4         int[] arr={1,2,3,4};  5         arrays.fill(arr,8);  6         for (int i =0;i 1 //使用arrays的tostring(int [] ,arr)方法把数组转换为字符串 2 class example{ 3     public void run() { 4         int[] arr={9,8,3,5,2}; 5         string arrstring=arrays.tostring(arr); //使用tostring()方法将数组转换为字符串 6             system.out.println(arrstring); 7     } 8 }
[9, 8, 3, 5, 2]
6、数组转成list集合——aslist() 。
             数组转成集合:就是为了使用集合的方法操作数组中的元素。
             但是不要使用增删等改变长度的方法。add remove 发生unsupportedoperationexception
             如果数组中存储的是基本数据类型,那么转成集合,数组对象会作为集合中的元素存在。数组中元素是引用数据类型时,转成,数组元素会作为集合元素存在。
           7、集合转成数组——toarray().
为什么集合转成数组呢?
为了限制对元素的增删操作。
如果传递的数组的长度小于集合的长度,会创建一个同类型的数组长度为集合的长度。
如果传递的数组的长度大于集合的长度,就会使用这个数组,没有存储元素的位置为null。
长度最好直接定义为何集合长度一致。
以上就是java之集合概述的详细内容。
其它类似信息

推荐信息