在数学中1、2、3、4等称为整数,1、2、1.5、3.4等称为有理数,这种数字的聚合就称为集合,在生活中也有集合之称,在超市购物的时候购物车就是你所买东西的集合,它是盛装具有共同属性的容器。那么java中也存在集合之说,到底什么是集合,集合有什么作用,为什么要用集合等一系列问题蜂拥而至,今天围绕5W1H粗略的总结一下,有不到之处还请不吝赐教。
一、什么是Java中的集合(What)
在Java中盛装任意数量的具有共同属性对象(此处是对象的引用,后面的对象也均代表对象的引用)的容器称为集合。
集合类型有三种:List、Set、Map.集合类存放于java.util包下,那么Java集合中都有哪些成员呢??
Java中的集合主要有两大家族---Collection和Map,Collection 是存储单独的对象引用<value>,而Map中存储的是键值对<key,value>,下图就是Collection 和Map两大族谱,其中有几个很重要的接口和实现类
在Collection 中List和Set接口分别是Collection 中比较重要的子接口,ArrayList、HashSet是应用较广的实现类,Map中比较重要的是HashMap实现类
这些接口都定义了哪些方法
Collection常用的方法:
boolean add(Object obj): 添加一个Object对象到Collection 中,如果对象已存在(值存在,并不是对象存在,即equals()的返回值为true,不是==)就返回false
boolean addAll(Collection<?> e): 将一个子集合添加到该集合中
boolean contains(Object obj): 集合中是否已经包含obj对象,同上,equals返回true
boolean containsAll(Collection<?> e): 判断一个集合中是否包含另一个集合中
boolean remove(Object obj) : 删除集合中的obj对象
boolean removeAll(Collection<E> e): 删除集合中的一个小集合
void clear(): 清空集合中的对象
int size(): 取得集合的长度
Object[] toArray(): 返回集合中的对象的数组(集合转换成数组)
Object[] toArray(Object[] obj): 把集合中的对象数组放在obj数组中,obj须事先创建好
boolean equals(): 判断两个对象是否相同(此时,默认的是进行引用比较,如果要比较值是否相同,就需要覆盖equals()方法和hashCode()方法,常规中规定,当两个对象equals()方法相同时,他们必须实现hashCode)
boolean isEmpty(): 判断集合是否为空(当集合中没有元素的时候返回true)
Iterator<E> iterator(): 返回在此collection 元素上进行迭代的迭代器
List常用的方法:
List继承自Collection ,表示的是序列,可以进行相应的指定位置的插入和删除,允许拥有重复值,有下标并且从0开始,除了从Collection 继承的方法以外,还有一些自定义的方法。另外:List中允许有多个null元素
Object set(int index, Object obj): 给集合中的index的位置添加元素,如果那个位置已经有了元素,则替换之
Object get(int index): 获取集合中index的位置的元素,如果没有则返回null
int indexOf(Object obj): 获取集合中的obj对象的位置,找到的话返回的是第一次的下标,没找到则返回-1
int lastIndexOf(Object obj): 返回列表中最后出现的元素的位置
ListIterator<E> listIterator(): 返回此列表中元素的列表迭代器(按适当的顺序)
ListIterator<E> listIterator(int index): 返回此列表中元素的列表迭代器(按适当的顺序)、从指定位置开始
List<E> subList(int start,int end): 返回此列表的子列表,从start开始,到end结束
Set继承了Collection 的所有的方法,但是是无序且不可重复的,规定其中只能有一个null元素。
Map常用的方法:
Map以映射的关系存在,其中的数据是一个一个的键值对----<key,value>,其中,key称为"键",是不可重复的,value被称为"值",可以重复,键到值的一个映射。
V put(Object key, Object value): 往Map集合中存键值对<key,value>,如果key存在,则用value替换原来的value
V get(Object key): 获取Map中的key值对应的元素value,若无,则返回null
int size(): 取得Map中的对象元素的个数
boolean isEmpty(): 如果此映射未含有key-value的映射关系,则返回true
Set<Map.Entry<K,V>> entrySet(): 返回此映射关系中包含的Set视图
boolean containsKey(Object key): 判断Map中是否含有key这个键
boolean containsValue(Object Value): 判断Map中是否含有value这个值
V remove (Object key): 删除Map中的key所对应的键值对
void clear(): 清空Map集合中的映射关系
Set <K> KeySet(): 获取Map中的所有的key 的set集
Collection<V> values(): 获取Map中的所有的value 的Collection集(因为set 中的元素不可以重复,所以接收KeySet的返回值,而value的值是可以重复的,所有接收values的返回值
二、为什么要用集合呢/在哪里用/什么时候使用/谁使用(why/when/where/who or which)
万物存在自然有它存在的道理,那么为什么会出现集合呢???它能干什么呢???
A.集合的作用
a.在类的内部可以对数据进行组织
b.集合中可以对大量的数据进行快速的查找搜索
c.有些集合接口可以提供快速的插入和删除一些元素的方法
d.有些接口提供了映射的关系,可以根据关键字key 去查找对应的value值
B.集合与数组的对比
a.数组的长度在创建的时候已经固定了,而集合的长度可以任意伸缩
b.在数组中是根据下标去访问具体的某一元素,但是很多时候并不直到某一元素的具体位置,这时候我们便可以根据集合提供的映射关系,根据他的关键字去查找对应的元素,且不限制类型
以上回答了为什么要使用集合,它有什么优点,使用了之后有什么好处。现在我们来说说集合在什么时候使用,谁在使用
当一个类的内部有大量的长度不确定的共同属性时会采用集合的方式进行管理。例如,学生选课时,学生所选的课程就是利用集合实现的,而学生的实例对象(即学生)就是使用集合的对象。
大概讲了一下集合,现在我们来看它是怎么被使用的
三、怎么使用集合(How)
Collection中的list使用方法:
public class Course { private int id; private String name; public int getId(){ return id; } public void setId(int id){ this.id = id; } public void setName(String name){ this.name = name; } public String getName(){ return name; } public Course(int id,String name){ this.id = id; this.name = name; } } package CollectionDemo; import java.util.HashSet; import java.util.Set; /** * 学生类 */ public class Student { private int id; private String name; public Set courses; public Student(int id,String name){ this.id = id; this.name = name; this.courses = new HashSet(); } public void setId(int id){ this.id = id; } public void setName(String name) { this.name = name; } public int getId() { return id; } public String getName() { return name; } } package CollectionDemo; import java.util.*; /** * 测试list的类 */ public class ListTest { public List courseToSelect; public ListTest(){ this.courseToSelect = new ArrayList(); } //list中的元素是有序并且可重复的 public void testAdd(){ //创建一个课程对象,并通过add方法添加到list中去 Course cr = new Course(1,"数据结构"); courseToSelect.add(cr); //通过get 方法获取所添加的课程 Course temp = (Course)courseToSelect.get(0); System.out.println("添加了课程:"+temp.getId()+":"+temp.getName()); //测试另一个add方法() Course cr2 = new Course(2,"数学"); courseToSelect.add(0,cr2); Course temp2 = (Course)courseToSelect.get(0); System.out.println("添加了课程: "+temp2.getId()+":"+temp2.getName()); //测试如果插入的位置超过数组的长度会怎么样 // // Course cr3 = new Course(3,"test"); // courseToSelect.add(4,cr3);//会抛出数组越界的异常 //测试添加的另一种方法,addAll() Course [] courses = {new Course(3,"大学英语"),new Course(4,"离散数学")}; /**
*将创建的数组转变成一个list,在源码中显示的是输入一个数组,
*return new ArrayList()的一个对象 */ courseToSelect.addAll(Arrays.asList(courses)); Course temp3 = (Course)courseToSelect.get(2); Course temp4 =(Course)courseToSelect.get(3); System.out.println("添加了课程:"+temp3.getId()+":"+temp3.getName()+";"+temp4.getId()+":"+temp4.getName()); //测试添加的另一种方法,addAll(int index,Object T) Course [] courses1 = {new Course(5,"高等数学"),new Course(6,"大学物理")}; courseToSelect.addAll(2,Arrays.asList(courses1)); /**
*在上方添加了数据后,后边的会自动向下移动
*/
Course temp5 =(Course)courseToSelect.get(2); Course temp6 =(Course)courseToSelect.get(3); System.out.println("添加了课程:"+temp5.getId()+":"+temp5.getName()+";"+temp6.getId()+":"+temp6.getName()); //测list 中可以重复添加元素 Course cr4 = new Course(2,"数学"); courseToSelect.add(0,cr4); Course temp7 = (Course)courseToSelect.get(0); System.out.println("添加了课程: "+temp7.getId()+":"+temp7.getName());//是可以添加的 } //编写一个循环访问list的方法 public void testVisit(){ System.out.println("有如下课程备选:"); int size = courseToSelect.size(); for(int i=0;i<size;i++){ Course cr = (Course)courseToSelect.get(i); //这里为什么会进行强转呢?因为在集合中默认添加进集合中的数据是Object,取出来的也是Object System.out.println("被选课程:"+cr.getId()+":"+cr.getName()); } } //通过迭代器循环访问数组,迭代器是依赖于集合而存在的,本身不具备存储元素的功能 public void testIterator(){ System.out.println("有如下的课程备选,通过迭代器来遍历的"); Iterator it = courseToSelect.iterator(); while(it.hasNext()){ Course cr = (Course)it.next(); System.out.println(cr.getId()+":"+cr.getName()); } } //通过for Each方法循环访问集合 public void testForEach(){ System.out.println("有如下课程备选:通过foreach访问"); //这里为什么是Object类型的呢?因为存入集合中的元素都会忽略原来的类型, // 当作是Object类型的,取出来的时候也是一样的 for(Object obj:courseToSelect){ Course cr = (Course)obj; System.out.println(cr.getId()+":"+cr.getName()); } } //修改集合上的元素,利用list的set(int index,Course cr); public void testModify(){ courseToSelect.set(0,new Course(7,"毛概")); } /** *删除课程有三种方法 * a.remove(Object obj) * b.remove(index) * c.removeAll() */ //删除的remove(Object obj) public void testRemove(){ // Course cr =(Course)courseToSelect.get(0); // System.out.println("我是课程:"+cr.getId()+":"+cr.getName()+",我即将被删除"); //删除的removeAll()方法,也是利用了删除了一个数组的方法 Course[] course = {(Course)courseToSelect.get(0),(Course)courseToSelect.get(1)}; courseToSelect.removeAll(Arrays.asList(course)); //删除remove(int index) // courseToSelect.remove(0); testForEach(); } //测试一下是否可以添加非指定类型的东西 public void testType(){ courseToSelect.add("我不是课程,我只是一个简单的字符串"); } public static void main(String[] args){ ListTest lt = new ListTest(); lt.testAdd(); /** * 集合中是不能添加一些其他类型的对象引用的,为什么呢?? * 因为一直以来都是给集合中添加的课程类型的,当取出来的时 * 候也要进行类型强转成Course类的,但是当取得的是字符串时,便不能将String * 转换成Course的引用,就会抛出异常,这时候便会出现了泛型,解决了这一类问题 * 因为泛型不允许添加其他类型的引用,它规定了特定的类型,当与指定的类型不一致时便会出现编译错误 */ lt.testType(); lt.testForEach(); lt.testVisit(); lt.testIterator();
lt.testForEach(); lt.testModify(); lt.testForEach(); lt.testRemove(); } }
下面是泛型的用法,泛型其实就是规定了集合必须的类型,如下的Student中的courses属性,就是一个带有泛型的课程集合,由于Course类,上面的代码中有,这里就不重复了
package CollectionDemo; package CollectionDemo; import java.util.HashSet; import java.util.Set; /** * 学生类 */ public class Student { private int id; private String name; public Set<Course> courses; public Student(int id,String name){ this.id = id; this.name = name; this.courses = new HashSet(); } public void setId(int id){ this.id = id; } public void setName(String name) { this.name = name; } public int getId() { return id; } public String getName() { return name; } } import java.util.ArrayList; import java.util.InputMismatchException; import java.util.List; /** * 一个简单的泛型,规定了特定的类型,不能随便添加其他的类型 * 并且返回值不再是Object类型的了,而是规定的类型 */ public class testGeneric { public List<Course> list; public testGeneric(){ this.list = new ArrayList<Course>(); } public void testAdd(){ Course cr = new Course(1,"大学语文"); list.add(cr); //测试是否可以添加子类型的对象引用 ChildCourse ccr = new ChildCourse(3,"大学体育"); list.add(ccr); Course cr2 = new Course(2,"java基础"); list.add(cr2); // list.add("我不是一个无辜的人"); //这里编译不会让其通过 } //基本类型不能作为类型传递给泛型 public void testBasicType(){ List <Integer> basice = new ArrayList<Integer>(); basice.add(1); System.out.println("泛型必须是包装类型:"+basice.get(0)); } public void testForEach(){ System.out.println("课程如下:"); for(Course cr : list){ System.out.println(cr.getId()+":"+cr.getName()); } } public static void main(String[] args){ testGeneric tg = new testGeneric(); tg.testAdd(); tg.testForEach(); tg.testBasicType(); } }
说完了泛型,这里说一下set的用法,其实和List的用法基本一致,只是它是无序的
package CollectionDemo; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner; public class SetTest { public List<Course> courseToSelect; public SetTest(){ courseToSelect = new ArrayList<Course>(); } public void testAdd(){ Course [] cr = {new Course(1,"计算即基础"),new Course(2,"python"), new Course(3,"C语言"),new Course(4,"java基础")}; courseToSelect.addAll(Arrays.asList(cr)); } public void testForEach(){ System.out.println("输出备选课程"); for(Course cr: courseToSelect){ System.out.println("备选课程:"+cr.getId()+":"+cr.getName()); } } public static void main(String[] args) { SetTest st = new SetTest(); st.testAdd(); st.testForEach(); //下面创建一个Student 的对象 Student sdt = new Student(1, "小花"); Scanner input = new Scanner(System.in); System.out.println("请输入数字进行选课:"); for (int i = 0; i < 3; i++) { int courseId = input.nextInt(); for (Course cr : st.courseToSelect) { if (cr.getId() == courseId) { sdt.courses.add(cr); //这里有用到set,因为课程courses的类型是set的 //set不能重复添加相同的元素,并且,每次多次添加相同的引用,set集中都是第一次 //且无序; 还可以添加null值 // sdt.courses.add(null); // sdt.courses.add(cr); //重复添加不会报错,但是并不会添加到集合中去 } } } st.testPrint(sdt); } //打印Student的属性 public void testPrint(Student s){ int size = s.courses.size(); //这里有调用了集合set的方法 System.out.println("共选择了"+size+"门课"); for(Course cr : s.courses){ //这里因为使用了泛型,所以他的类型是确定,便可直接使用Course System.out.println(cr.getId()+":"+cr.getName()); } } }
map的使用:
package CollectionDemo; import java.util.*; public class MapTest { public Map<Integer, Student> students; public MapTest() { this.students = new HashMap<Integer, Student>(); } //测试map 的添加方法,put /** * 输入学生的id,在集合中查找是否存在,若存在便返回学生id已存在 * 若不存在,则重新创建一个对象进行添加 */ public void testPut() { Scanner input = new Scanner(System.in); int i = 0; while (i < 3) { System.out.println("请输入学生的ID:"); int ID = input.nextInt(); Student st = students.get(ID); if (st == null) { System.out.println("请输入学生的姓名:"); String name = input.next(); Student newStudent = new Student(ID, name); students.put(ID, newStudent); System.out.println("学生:" + name + "添加成功"); i++; } else { System.out.println("您输入的学生的id 已存在,请重新输入"); continue; } } } //测试remove 删除方法 public void testRemove() { Scanner input = new Scanner(System.in); while (true) { System.out.println("请输入您要删除的学生id"); int id = input.nextInt(); Student st = students.get(id); if (st == null) { System.out.println("您输入的学生不存在,请重新输入"); continue; } else { System.out.println("删除学生" + st.getName()); Student stt= students.remove(id);//返回的是被删除的对象 System.out.println("删除成功"); break; } } } //测试map 的entrySet 方法 public void testEntrySet() { Set<Map.Entry<Integer, Student>> entrySet = students.entrySet(); System.out.println("一共有" + students.size() + " 个学生"); for (Map.Entry<Integer, Student> entry : entrySet ) { System.out.println("学生:" + entry.getKey() + ": " + entry.getValue().getName()); } } //测试keySet方法,获取集合中的key public void testKeySet() { Set<Integer> keySet = students.keySet(); System.out.println("集合中的学生的总数:" + students.size()); for (Integer stuID : keySet ) { System.out.println("学生:" + students.get(stuID).getName()); } } //测试map 的修改方法modify public void testModify() { Scanner input = new Scanner(System.in); while (true) { System.out.println("请输入您要修改的学生的id"); int id = input.nextInt(); Student st = students.get(id); if (st == null) { System.out.println("您输入的学生不存在,请重新输入"); continue; } else { System.out.println("学生是" + id + " " + st.getName()); System.out.println("请输入您要修改的学生姓名"); String name = input.next(); Student newStudent = new Student(id, name); students.put(id, newStudent); System.out.println("修改成功" + " 学生现在是:" + id + " : " + students.get(id).getName()); break; } } } public static void main(String[] args) { MapTest mt = new MapTest(); mt.testPut(); mt.testKeySet(); //为什么这里输出的总是有序且不变的,imooc上说是无序的??是的,API上也说是无序的,但是我的电脑上跑出来就是有序的 // mt.testRemove(); // mt.testEntrySet(); mt.testModify(); mt.testEntrySet(); } }
以上就是今天关于集合的大概总结,还请大神赐教!!!