Java基础_Collection学习(List Set)

Oriel ·
更新时间:2024-11-13
· 971 次阅读

Collection

点击跳转到指定介绍

list & Set

list

下面是他们的关系表

–Collection–(单列集合) –|----> List–(有序、可重复数据) —||----> ArrayLis–(主要实现类) —||----> LinkedList (看情况) —||----> Vector–(古老实现类)

Collection接口–>常用方法应用:

import com.sun.org.apache.xpath.internal.operations.String; import org.junit.Assert; import org.junit.Test; import java.util.*; /*** * Collection接口的应用测试类 * 建议导入org.junit.Test,采用@test * 这里讲 Collection 接口的常用方法! * * @author: G_night * 转载请声明作者 * Reprint please state the author ***/ public class MyCollection { /** * add() \ contains() \ remove() * 添加 || 查询是否包含 || 移除 **/ @Test public void test_1(){ Collection coll = new ArrayList(); //add添加元素 coll.add(123); coll.add("Wang"); coll.add(new Person("Liu",11)); //contains(Object obj)判断是否包含 boolean bool_123=coll.contains(123); System.out.println(bool_123); System.out.println(coll.contains("Wang")); System.out.println(coll.contains(new Person("Liu",11))); /* 其实contains比较调用的是equals 因为String的重写了String所以是比较内容,故返回true 而Perosn还没有重写,所以返回false 如果要返回true,那就重写equals吧(示例的person已经重写了equals) */ //containsAll(Collection new_coll); //判断new_coll的元素是否都存在coll中 Collection new_coll = Arrays.asList(123,new Person("Liu",11)); System.out.println("是否都包含:"+coll.containsAll(new_coll)); //remove(element) 移除元素,会先使用equals去找有没有一样的,再移除, //所以也要重写equals //该remove只能移除第一个,所以还是显示true coll.add(new Person("Liu",11)); coll.remove(new Person("Liu",11)); System.out.println("第一次移除:"+coll.contains(new Person("Liu",11))); //removeAll会移除coll中re_coll的元素,并且不是只移除一个而是后面多个都一起移除 Collection re_coll=Arrays.asList(new Person("Liu",11)); coll.removeAll(new_coll); System.out.println("第二次移除:"+coll.contains(new Person("Liu",11))); } /** * retainAll() 求交集 * toArray() 集合变数组 -> 便于Collection遍历查看 * hashcode() 求hashcode **/ @Test public void test_2(){ Collection coll=new ArrayList(); coll.add(123); coll.add(new Person("Liu",12)); Collection t_coll=Arrays.asList(123); //求coll和t_coll的交集,并赋值给coll //求交集前 System.out.println("求交集前:"); Object[] arr=coll.toArray();//toArray是为了方便遍历 for(int i=0;i<arr.length;i++){ System.out.println(arr[i]); } //求交集后 System.out.println("\n求交集后:"); coll.retainAll(t_coll); arr=coll.toArray();//toArray是为了方便遍历 for(int i=0;i 为容器而生 * 如果是List 可以使用iterator.hasNext()遍历 ArrayList * 还有一些列迭代器的应用案例 * 注:ArrayList 还可以使用 list.get(i) 遍历 **/ @Test public void test_3(){ Collection coll=new ArrayList(); coll.add(123); coll.add("Wang"); coll.add(new Person("Liu",12)); coll.add(false); System.out.println("iterator遍历方式:"); Iterator iterator=coll.iterator(); while(iterator.hasNext()){ // 案例一、移除Wang Object obj=iterator.next();//先放到obj做判断操作 System.out.println(obj); if("Wang".equals(obj)){ iterator.remove(); } } // 案例二、再次刷新迭代器的指针,回到头部 // 发现上一次的“Wang”成功删除 System.out.println("\n第二次遍历:"); iterator=coll.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } } }

使用到的Person类:

import java.util.Objects; /*** * 测试采用的Person类 * * @author: G_night * 转载请声明作者 * Reprint please state the author ***/ public class Person { private String name; private int age; Person(String name,int age){ setName(name); setAge(age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } /* 重写equals,最好配上hashcode */ @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } } List接口及其实现类 – 详解

ArrayList是使用object[] element存储、线程不安全、效率高;

Vector是使用object[] element存储、线程安全、效率低;

LinkedList是使用双向链表存储、插入和删除效率比ArrayList更高,不过不支持随机访问,访问效率不如ArrayList

问:那么三者有什么异同吗?

相同点:都实现了List接口,存储数据的特点相同,都是有序的,课程夫的数据
不同点:线程安全和效率不同,底层实现也有所不同,看上面~

LIst接口的常用方法(对Collection接口的补充) package com.zzt.MyLIst;/* * @author: G_night * 转载请申明作者 * Reprint please state the author */ import org.junit.Test; import java.util.ArrayList; import java.util.Iterator; public class MyListTemplate { @Test public void test1(){ //初始化 ArrayList list=new ArrayList(); list.add(123); list.add("Wang"); list.add(false); list.add(123); //indexof()返回第一次出现的位置,从0开始,未找到就返回-1 int index=list.indexOf(123); System.out.println("123第一次出现的位置:"+index); //lastindexof()返回最后一次出现的位置 int lastindex=list.lastIndexOf(123); System.out.println("123最后一次出现的位置:"+lastindex); //remove有两种,一个是移除对象,一个是按照index移除 // (移除对象,没有的话不会跑出错误)(按照index移除,越界会抛出错误) list.remove(0); list.remove(new Integer(1234)); //set(index,element),在指定index修改元素 //最后输出的时候,会发现“Wang”也不见了 //这是因为移除了第一个后,后面的元素往前移动了, // 然后又使用了set覆盖了第0个的元素,故“Wang”消失了 list.set(0,123); Iterator it=list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } System.out.println("\n获取index=1元素:"+list.get(1)); } } 底层实现情况 – 简述

ArrayList:

package diceng;/* * @author: G_night * 转载请申明作者 * Reprint please state the author */ import java.util.ArrayList; public class MyArrayList { public static void main(String[] args) { //JDK1.7 ArrayList arrayList=new ArrayList();//底层创建了,长度为10的数组 Object[] // 每次添加数组,都会判断是否会溢出,溢出的话就扩容为原来的1.5倍(默认) //JDk1.8 ArrayList arrayList_1_8=new ArrayList();//此时还没有创建长度为10的数组 arrayList_1_8.add(123);//此时才创建了长度为10的数组 // 所以jdk8更加节省内存,延迟了创建 } }

LinkedList:

package diceng;/* * @author: G_night * 转载请申明作者 * Reprint please state the author */ import java.util.LinkedList; public class MyLinkedList { public static void main(String[] args) { LinkedList linkedList=new LinkedList(); //声明了Node类型的first和last属性,默认值为null //相对于ArrayList,LinkedList更适合频繁插入删除, //因为采用的是双向链表 } } //Node(原生的是private static)的定义方式: class Node{ E item; Node next; Node prev; Node(Node prev,E element,Node next){ this.item=element; this.next=next; this.prev=prev; } } 总结

List方法的增、删、查、改,插入、遍历、求交集:

增:add(element) 删:remove(obj) 查:indexof(obj) 改:set(inedx,element) 插入:add(index,element) 这个是在index前一位加入哦 遍历:使用iterator等等 求交集:retains(element) or retainsAll(obj) Set

下面是他们的关系表

–Collection–(单列集合) –|----> Set–(无序、不可重复数据) —||----> HashSet–(主要实现类) ------|||----> LinkedHashSet (HashSet的子类,可按插入顺序遍历数据) —||----> TreeSet–(底层红黑树,按照指定属性进行排序)

无序性 != 随机性

无序性是指存储的按照哈希值排序,而不是按照插入顺序排序

要明白一点:哈希值一样不代表该元素完全相同

HashSet

底层是一个数组 Object[]

通过hashCode()equals()判断是否为相同的元素

所以往HashSet添加元素前,一定要重写hashCode()equals()

具体判断过程为:

计算出哈希值,看索引位置是否有元素了,没有的话添加成功 如果有该哈希值,那么调用equals()判断是否相同,如果相同添加失败,不相同就添加成功 示例: package com.zzt.MySet;/* * @author: G_night * 转载请申明作者 * Reprint please state the author */ import org.junit.Test; import com.zzt.MySet.Person; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class MySetTemplate { /** * Set没有新的方法,都是Collection接口的方法实现 **/ @Test public void test1(){ Set set=new HashSet(); set.add(456); set.add("AA"); set.add(new Person("Liu",12));//Person类见上面Collection的示例 Iterator it=set.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } }

拓展:

为什么重写HashCode方法,采用了31这个数字?

原因:

31只占5bits,乘法造成数据溢出的概率小 i*31 == (i< 结果只能被素数本身还有1来整除 LinkedHashSet

LinkedHashSetHashSet其实存储方式是一样的,都是放在数组中,但是他们多了一个前置和后置的索引,故使用iterator索引的时候,会按照插入顺序显示出来!

LinkedHashSet对于频繁的遍历操作比HashSet更好

TreeSet

优势:规定顺序排序,查询速度比List快

注意事项:

TreeSet不能再一个Set对象中添加不同类的对象 分 自然排序 & 规定排序 -> 需要重写compareTo 重写步骤: 类添加 implements Comparable; 重写compareTo
重写实例(根据Person来修改): package com.zzt.MySet; import java.util.Objects; /*** * 测试采用的Person类 * 这里添加了compareTo用于TreeSet * @author: G_night * 转载请声明作者 * Reprint please state the author ***/ public class Person implements Comparable{ private String name; private int age; Person(String name, int age){ setName(name); setAge(age); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } /* 重写equals,最好配上hashcode */ @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } @Override public int compareTo(Object obj){ if(obj instanceof Person){ Person person=(Person) obj; //用name&age是否相同作为判断,并按照姓名顺序来比较 if(this.age==person.age&&this.name.equals(person.name)){ return 0; } return this.name.compareTo(person.name); }else{ throw new RuntimeException("类型不匹配"); } } }

我们还可以自己在test程序中写方法定义排序(见test2):

package com.zzt.MySet;/* * @author: G_night * 转载请申明作者 * Reprint please state the author */ import org.junit.Test; import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; public class MyTreeSet { @Test public void test1(){ TreeSet set=new TreeSet(); set.add(new Person("Liu",12)); set.add(new Person("Liu",12)); set.add(new Person("Aang",12)); Iterator it=set.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } @Test public void test2(){ Comparator com=new Comparator() { @Override public int compare(Object o1, Object o2) { if(o1 instanceof Person && o2 instanceof Person){ Person p1=(Person) o1; Person p2=(Person) o2; return Integer.compare(p1.getAge(),p2.getAge()); }else{ throw new RuntimeException("类型不匹配"); } } }; TreeSet set=new TreeSet(com); set.add(new Person("Liu",12)); set.add(new Person("Liu",12)); set.add(new Person("Aang",18)); Iterator it=set.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } }
作者:PHOloe



collection java基础 JAVA set list

需要 登录 后方可回复, 如果你还没有账号请 注册新账号