集合和数组一样,可以保存一组元素,但是集合将元素的操作都封装成了方法,操作简便。
集合只能存放引用类型
java.util.Collection是所有集合的顶级接口,里面定义了所有集合都必须具备的功能方法
集合有两类常用的子类:
* java.util.List:可重复的集合,且有序。通常我们称它为"线性表"
* java.util.Set:不可重复的集合。linkedhashset是有序集合。
上述两个都是接口,而元素是否重复取决于元素自身的equals方法,即:Set集合中不会存在
两个元素equals比较为true的情况。
Collection常用方法
public class CollectionDemo1 { public static void main(String[] args) { //Collection c = new ArrayList(); Collection c = new HashSet();//java.util.HashSet,不可重复的集合 //集合只能存放引用类型 // c.add(123);//会触发自动装箱特性 /* boolean add(E e) 向当前集合中添加一个元素,如果该元素成功添加则返回true,否则返回false */ c.add(new Point(1,2)); c.add(new Point(3,4)); c.add(new Point(5,6)); c.add(new Point(7,8)); c.add(new Point(9,0)); c.add(new Point(1,2));//重复元素无法放入Set集合两次 /* 集合重写了toString方法,格式为: [元素1.toString(), 元素2.toString(), 元素3.toString(), ....] */ System.out.println(c); /* int size() 返回当前集合的元素个数 */ int size = c.size(); System.out.println("size:"+size); /* boolean isEmpty() 判断当前集合是否为一个空集.当size为0时,返回true。 */ boolean isEmpty = c.isEmpty(); System.out.println("是否为空集:"+isEmpty); Point p = new Point(1,2); /* boolean contains(Object o) 判断当前集合是否包含给定元素。 元素是否包含取决于该元素是否与集合现有元素存在equals比较为true的情况 */ boolean contains = c.contains(p); System.out.println("是否包含该元素:"+contains); /* remove方法删除元素时也是删除与集合中equals比较为true的元素。 注:对于List而言,由于可以存放重复元素,对这种情况仅会删除一次。 */ c.remove(p); System.out.println(c); /* void clear() */ c.clear(); System.out.println(c);//[] System.out.println("size:"+c.size());//0 System.out.println("是否为空集:"+c.isEmpty());//true } }
/** * 集合间的操作 */ public class CollectionDemo4 { public static void main(String[] args) { Collection c1 = new HashSet(); c1.add("java"); c1.add("c++"); c1.add(".net"); System.out.println("c1:"+c1); Collection c2 = new ArrayList(); c2.add("android"); c2.add("ios"); c2.add("java"); System.out.println("c2:"+c2); /* boolean addAll(Collection c) 将给定集合中的所有元素添加到当前集合中(取并集) 操作后当前集合发生了改变则返回true */ c1.addAll(c2); System.out.println("c1:"+c1); System.out.println("c2:"+c2); Collection c3 = new ArrayList(); c3.add("c++"); c3.add("ios"); c3.add("php"); System.out.println("c3:"+c3); /* boolean containsAll(Collection c) 判断当前集合是否包含给定集合中的所有元素 */ boolean containsAll = c1.containsAll(c3); System.out.println("包含所有:"+containsAll); /* 取交集 */ c1.retainAll(c3);//c1有变化,c3不变 System.out.println("c1:"+c1); System.out.println("c3:"+c3); /* 删除交集。将c1中与c3的共有元素删除(c3不受影响) */ c1.removeAll(c3); System.out.println("c1:"+c1); System.out.println("c3:"+c3); } }
集合与内存之间的关系
public class CollectionDemo3 { public static void main(String[] args) { Collection c = new ArrayList(); Point p = new Point(1,2); c.add(p);//将p元素存入集合 System.out.println("p:"+p);//(1,2) System.out.println("c:"+c);//[(1,2)] p.setX(2);//将p对象中的x属性改为2 System.out.println("p:"+p);//(2,2) System.out.println("c:"+c);//[(2,2)] } }
集合遍历方式:迭代器模式
对应方法:
Iterator iterator()
java.util.Iterator是迭代器接口,定义了迭代器遍历集合的基本操作,所有的集合都提供了一个用于遍历自身元素的迭代器实现类,我们无需记住他们的名字,用多态的思想将他们统一看做是Iterator即可。迭代器遍历集合遵循的步骤:问hasNext()->取.next()->删it.remove()。其中删除不是必须操作。迭代器在遍历的过程中不能通过集合的方法增删元素,否则迭代器会抛出并发修改异常:java.util.ConcurrentModificationException
public class IteratorDemo { public static void main(String[] args) { Collection c = new ArrayList(); c.add("one"); c.add("#"); c.add("two"); c.add("#"); c.add("three"); System.out.println(c); //获取迭代器 Iterator it = c.iterator(); /* boolean hasNext() 判断集合是否还有"下一个"元素可以遍历。迭代器的起始位置可以理解为是集合第一个 元素位置之前。因此第一次调用hasNext()就是判断集合是否有第一个元素。 E next() 获取集合中"下一个"元素。获取后迭代器的位置会向后移动一个元素位置 */ while(it.hasNext()){ String e = (String)it.next(); System.out.println(e); if("#".equals(e)){ /* 迭代器在遍历的过程中不能通过集合的方法增删元素,否则迭代器会 抛出并发修改异常: java.util.ConcurrentModificationException */ // c.remove(e); /* 迭代器提供了remove方法可以将本次通过next方法获取的元素从集合 中删除。 */ it.remove(); } } System.out.println(c); } }
集合遍历方式:增强型for循环
语法: 循环遍历时会被编译器改回成传统for循环遍历
for(元素类型 e : 集合或数组){
//执行代码块
}迭代器与增强型for循环的区别:
在编译的时候,如果遍历的是数组,编译器会将增强型for循环改为for循环的形式;如果遍历的是集合,编译器会将增强型for循环改为迭代器的形式,而且直接使用迭代器可以对集合元素进行删除操作,而增强型for循环不可以进行此操作。数组增删操作不受限制。
public class NewForDemo { public static void main(String[] args) { String[] array = {"one","two","three","four","five"}; for(int i=0;i<array.length;i++){ String s = array[i]; System.out.println(s); } for(String s : array){ System.out.println(s); } /* JDK5之后还推出了一个特性:泛型 泛型也称为参数化类型,它的原型就是Object,泛型的目的是让我们将定义的Object 类型当做什么看待。 例如下面的集合中保存的每个元素都是用Object接收的,但是集合将它改成了E类型 这样一来,我们在使用集合时可以告知集合应当将E当做什么类型看待。 */ Collection<String> c = new ArrayList<>(); c.add("一");//编译器会检查传入的E对应的实参是否为E指定的实际类型 c.add("二"); c.add("三"); // c.add(1);//当实参不符合E指定的实际类型时,编译不通过 //新循环遍历集合就是迭代器,编译器会将其改回成迭代器遍历 for(String str : c){ System.out.println(str); } //改回成下面的样子 //Iterator<String> it = c.iterator(); Iterator it = c.iterator(); while(it.hasNext()){ String str = (String) it.next(); System.out.println(str); } } }
java.util.List接口
List继承自Collection,是最常用的一类集合。
特点:可以存放重复元素且有序。List里提供了一套可以通过下标操作元素的方法。
常用实现类:
java.util.ArrayList:内部使用数组实现,查询性能更好。
java.util.LinkedList:内部使用链表实现,增删性能更好,首尾增删性能最佳。
对性能没有特别苛刻的要求下,通常使用ArrayList即可。public class ListDemo { public static void main(String[] args) { List<String> list = new ArrayList<>(); // List<String> list = new LinkedList<>(); list.add("one"); list.add("two"); list.add("three"); list.add("four"); list.add("five"); System.out.println(list); /* void add(int index)//默认把该元素添加到集合后面 void add(int index,E e) 将给定元素插入到指定位置,后面元素往后移 */ //[one,two,three,six,four,five] list.add(3,"six"); System.out.println(list); /* E get(int index) 获取指定下标处对应的元素 */ String str = list.get(2);//与数组获取元素功能一致 String str = arr[2]; System.out.println(str); //List也可以通过循环下标的方式遍历 for(int i=0;i<list.size();i++){ str = list.get(i); System.out.println(str); } /* E set(int index,E e) 将给定元素设置到指定位置上,返回值为该位置原来的元素 替换元素操作 */ //[one,six,three,four,five] String old = list.set(1,"six");//将第二个位置原来的two返回 System.out.println(list); System.out.println(old); /* E remove(e)删除元素时也是删除与集合中equals比较为true的元素。 注:对于List而言,由于可以存放重复元素,对这种情况仅会删除一次。 E remove(int index) 删除并返回指定位置上的元素 */ //[one,two,six,four,five] String old = list.remove(2); System.out.println(list); System.out.println(old); //在不创建新集合的前提下,将集合元素翻转 for(int i=0;i<list.size()/2;i++){//i:0 // //获取正数位置上的元素 // String e = list.get(i);//one // //将正数位置上的元素来替换倒数位置上的元素 // e = list.set(list.size()-1-i,e);//five // //将原倒数位置上的元素设置到正数位置上 // list.set(i,e); list.set(i,list.set(list.size()-1-i,list.get(i))); } //[five,six,three,four,one] System.out.println(list); /* Collections是集合的工具类 该工具类为集合提供了很多API */ Collections.reverse(list);//翻转集合 System.out.println(list); } }
List集合提供获取子集的方法:
List subList(int start,int end)//获取当前集合中指定范围内的子集。对子集的操作就是对原集合对应元素的操作,对原集合进行修改,子集合会报并发修改异常,如果需要对原集合进行修改,可以重新创建一个集合,将原集合元素重新加载到新集合中,在对新集合进行操作
public class ListDemo3 { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); for(int i=0;i<10;i++){ list.add(i); } System.out.println(list); //获取子集[3-7] List<Integer> subList = list.subList(3,8); System.out.println("sub:"+subList); //将子集每个元素扩大10倍 for(int i=0;i<subList.size();i++){ subList.set(i,subList.get(i)*10); } //[30,40,50,60,70] System.out.println("sub:"+subList); /*对子集的操作就是对原集合对应元素的操作*/ System.out.println(list); //清除集合中1-8这部分元素 list.subList(1,9).clear(); System.out.println(list); } }
集合与数组间的转化
集合转化为数组
toArray(new String[c.size()])中
①如果集合是数组类型时new String[0]性能会更好,因为该集合本身就是一个数组,直接用就可以
②如果new String[c.size()]中指定的长度小于集合长度,则以集合长度为准,返回对应长度的数组
③如果new String[c.size()]中指定的长度大于集合长度,则以指定长度为准,返回对应长度的数组,其他位置以默认值填充/** * 集合转换为数组 * Collection定义了方法toArray可以将一个集合转换为一个数组 */ public class CollectionToArrayDemo { public static void main(String[] args) { Collection<String> c = new ArrayList<>(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); System.out.println(c); // Object[] array = c.toArray(); String[] array = c.toArray(new String[c.size()]); /*c.toArray(new String[c.size()])中如果集合是数组类型时new String[0]性能会更好,因为该集合本身就是一个数组,之间用就可以 如果new String[c.size()]中指定的长度小于集合长度,则以集合长度为准,返回对应长度的数组 如果new String[c.size()]中指定的长度大于集合长度,则以指定长度为准,返回对应长度的数组,其他位置以默认值填充*/ System.out.println(array.length); System.out.println(Arrays.toString(array)); } }
数组只能转换为List集合
数组的工具类Arrays提供了一个静态方法asList,可以将一个数组转换为一个List集合
对该集合的操作就是对原数组对应的操作,但是对该数组的操作不会影响该集合
由于数组是定长的,因此对集合增(add)删(remove)元素会导致对数组进行同等操作,这时会抛出异常:UnsupportedOperationException
如果有增删需求,则需要另外创建一个集合,并先将数组转换的集合内容导入后方可进行。
public class ArrayToListDemo { public static void main(String[] args) { String[] array = {"one","two","three","four","five"}; System.out.println("Array:"+Arrays.toString(array)); List<String> list = Arrays.asList(array); System.out.println("List:"+list); //对该集合的操作就是对原数组对应的操作 list.set(1,"six"); System.out.println("List:"+list); System.out.println("Array:"+Arrays.toString(array)); //如果有增删需求,则需要另外创建一个集合,并先将数组转换的集合内容导入后方可进行。 // List<String> list2 = new ArrayList<>(); // list2.addAll(list); /* 所有集合都支持一个参数为Collection的构造器,目标是在创建当前集合 的同时包含给定集合中的所有元素,注意list类型的参数给set类型时,可能会导致丢失部分数据 */ List<String> list2 = new ArrayList<>(list); System.out.println("list2:"+list2); list2.add("seven"); System.out.println("list2:"+list2); } }
List集合的排序
集合的工具类java.util.Collections提供了一个静态方法sort,可以对List集合进行自然排序
①Collections.sort(List list)在排序List集合时要求集合元素必须实现了,Comparable接口。实现了该接口的类必须重写一个方法compareTo用与定义比较大小的规则,从而进行元素间的比较后排序。否则编译不通过。
侵入性:
当我们调用某个API时,其反过来要求我们为其修改其他额外的代码,这种现象就成为侵入性。侵入性不利于程序后期的维护,尽可能避免。
②sort(list,com)重载方法com是定义的比较规则(推荐使用)public class SortListDemo2 { public static void main(String[] args) { //①实现Comparable接口,可以直接进行排序 List<Integer> list1 = new ArrayList<>(); Random random = new Random(); for(int i=0;i<10;i++){ list1.add(random.nextInt(100)); } System.out.println(list1); Collections.sort(list1); System.out.println(list1); //②sort的重载方法自定义排序方法 List<Point> list2 = new ArrayList<>(); list2.add(new Point(1,2)); list2.add(new Point(97,88)); list2.add(new Point(7,6)); System.out.println(list2); // Collections.sort(list2); Collections.sort(list2,new Comparator<Point>() { public int compare(Point o1, Point o2) { /** * 实现比较器接口后必须重写方法compare. * 该方法用来定义参数o1与参数o2的比较大小规则 * 返回值用来表示o1与o2的大小关系 */ int len1 = o1.getX() * o1.getX() + o1.getY() * o1.getY(); int len2 = o2.getX() * o2.getX() + o2.getY() * o2.getY(); return len1-len2; } }); System.out.println(list2); //③字符串排序 List<String> list = new ArrayList<>(); list.add("侠侣"); list.add("雕"); list.add("传奇故事"); System.out.println(list); // Collections.sort(list);字符串默认按照Unicode进行排序 //定义一个比较器,按照字多字少排序 Collections.sort(list,(o1,o2)->o1.length()-o2.length()); // Collections.sort(list, Comparator.comparingInt(String::length)); } }
java.util.Map接口
Map体现的结构是一个多行两列的表格,其中左列称为"key",右列称为"value"
Map总是以key-value对的形式保存一组数据。并且可以根据key获取对应的value。
Map有一个要求,key不允许重复(equals比较)
常用实现类:
java.util.HashMap,我们称它为"散列表"。当今查询速度最快的数据结构。
map的常用API:
public class MapDemo { public static void main(String[] args) { Map<String,Integer> map = new HashMap<>(); /* V put(K k,V v) 向当前Map中保存一组键值对 */ map.put("语文",99); //如果Map的value是包装类类型,获取时不要用基本类型接收,避免自动拆箱引发空指针 Integer value = map.put("数学",98);//key不存在时,put方法返回值为null System.out.println("value:"+value); map.put("英语",97); map.put("物理",96); map.put("化学",99); System.out.println(map); value = map.put("数学",77);//key已经存在则替换value,返回值为key原来对应的value System.out.println("value:"+value); System.out.println(map); /* V get(Object key) 根据给定的key获取对应的value,如果给定的key不存在,则返回值为null */ value = map.get("语文"); System.out.println("语文:"+value); value = map.get("体育"); System.out.println("体育:"+value); //返回当前Map中的元素个数 int size = map.size(); System.out.println("size:"+size); /* 删除给定的key对应的这组键值对,返回值为这个key对应的value */ value = map.remove("数学"); System.out.println(map); System.out.println("value:"+value); //可以分别判定Map是否包含给定的key或value。判定依据仍然是equals方法。 boolean ck = map.containsKey("英语"); System.out.println("包含key:"+ck); boolean cv = map.containsValue(97); System.out.println("包含value:"+cv); boolean n = map.isEmpty(); System.out.println("map是否为空集合:"+n); map.clear(); System.out.println(map); } }
Map的遍历
Map支持三种遍历方式:
* 1:单独遍历key
* 2:遍历每一组键值对
* 3:单独遍历value(这个操作不常用)
public class MapDemo2 { public static void main(String[] args) { Map<String,Integer> map = new HashMap<>(); map.put("语文",99); map.put("数学",98); map.put("英语",97); map.put("物理",96); map.put("化学",99); System.out.println(map); /* Set keySet() 将当前Map中所有的key以一个Set集合形式返回。 */ Set<String> keySet = map.keySet(); for(String key : keySet){ System.out.println("key:"+key); } /* 遍历每一组键值对 Set entrySet() 将当前Map中每一组键值对以Entry实例形式表示并存入集合后返将其返回。 java.util.Map.Entry它的每一个实例用于表示一组键值对 */ Set<Map.Entry<String,Integer>> entrySet = map.entrySet(); for(Map.Entry<String,Integer> e : entrySet){ String key = e.getKey(); Integer value = e.getValue(); System.out.println(key+":"+value); } /* Collection values() 将所有的value以一个集合的形式返回。 */ Collection<Integer> values = map.values(); for(Integer value : values){ System.out.println("value:"+value); } /* JDK8之后集合和Map都支持了基于lambda表达式形式遍历。 */ //Map会将每一组键值对作为参数传给lambda表达式 map.forEach( (k,v)-> System.out.println(k+":"+v) ); Collection<String> c = new ArrayList<>(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); // c.forEach( // e->System.out.println(e) // ); c.forEach( System.out::println ); } }