Collection接口
集合是一种用来存储数据的容器,不需要考虑容量问题,会自动扩容
Collection接口是构造集合框架的基础,是单值数据操作的最大父接口,所谓单值数据操作的意思即,每个元素都是单一的值,类似于数组的感觉。Collection接口包含了两个子接口List和Set,Collection接口定义的很多方法,List和Set接口都继承了下来。在开发的过程中也很少直接使用Collection接口,而是更多的去使用List和Set这两个子接口
1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
2. Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
3. List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector>
List子类型:ArrayList(不安全高效,查询快,增删慢),LinkedList(增删快,查询慢),Vector(安全低效)
List接口的使用
代码演示:
package demo; import java.util.ArrayList; import java.util.List; public class CollectionDemo { public static void main(String[] args) { //创建一个ArrayList对象 List list = new ArrayList(); /* * 往集合存放放数据(元素) * add(Object e)可以存放任何引用类型 */ list.add("one");
//一般会使用new Integer(5),这里自动包装 list.add(1);//集合也重写了toString()方法,在输出时,会调用元素的toString()方法System.out.println(list);}}
代码结果:
[one, 1]
代码讲解:上述代码声明父类接口List,用子类型ArrayLsit去实例化,然后调用add()方法,向列表里面添加元素,因为集合也重写了toString()方法,所以直接输出对象即可。
上述例子我们可以看到,我们存放了一个字符串,和一个整数,而我们模拟想做的是一个数组,显然不同的数据类型在集合没加泛型的情况下,都能存放进集合类,我们看add(Object obj)方法,可以看到参数上,只要是类即可,第一点:即只要是类即可插入,因为所有类的顶层都是Object类。第二点:泛型机制不支持基本数据类型,即类型参数不包含基本数据类型,我们来演示一下泛型的使用
代码演示:
package demo; import java.util.ArrayList; import java.util.List; public class CollectionDemo2 { public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); list.add(2); list.add(3); list.add(new Integer(5)); /* * list.add("1");会出现错误,因为泛型的限制,错误信息如下 * The method add(Integer) in the type List<Integer> is not applicable for the arguments (String) * list.add("1"); */ System.out.println(list); } }代码结果:
[2, 3, 5]
代码讲解:可以看到上述代码,泛型机制的引用也是十分简单的只需要List<T> list = new ArrayList<T>();即可
T可以换成其他类型,但不支持基本数据类型。
我们提到过,List可以实现动态数组,即大小不用一开始就确定好。我们来检验一下
代码演示:
package lesson1015_2; import java.util.ArrayList; import java.util.List; public class CollectionDemo2 { public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); list.add(2); list.add(5); list.add(8); list.add(9); //调用size()方法,查看List集合的长度 System.out.println(list.size()); //接着添加数据,观察List集合的长度变化 list.add(3); System.out.println(list.size()); } }
代码结果:
4 5
代码讲解:通过上述例子,我们可以看到List集合不但可以通过泛型模拟数组,而且是动态增长的,即当需要添加一个元素,它会直接分配一个位置,并且存入元素的值。在内存上说,List集合相对数组来说还是比较友好的
接下来我们将统一的给大家演示一下ArrayList的其他方法
代码演示:
package demo; import java.util.ArrayList; import java.util.List; public class CollectionDemo2 { public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); list.add(new Integer(5)); list.add(new Integer(8)); list.add(new Integer(9)); list.add(new Integer(0)); list.add(new Integer(5)); list.add(new Integer(1)); list.add(new Integer(4)); //使用add(int index,Object obj)向指定位置插入元素,当前位置,和当前位置后元素响应后移一位,index从0开始 list.add(2, new Integer(6)); System.out.println(list); //[5, 8, 6, 9, 0, 5, 1, 4] //使用remove(Object obj)移除一个元素 list.remove(new Integer(5)); System.out.println(list); //[8, 6, 9, 0, 5, 1, 4] //使用remove(int index)移除指定位置的元素 list.remove(3); System.out.println(list); //[8, 6, 9, 5, 1, 4] /* * 集合中也提供类似字符串的方法 * indexOf(Object obj):返回元素第一次出现的位置 * LastIndexOf(Object obj):返回元素最后一次出现的位置 */ int index = list.indexOf(new Integer(6)); int lastindex = list.lastIndexOf(new Integer(6)); System.out.println("6第一次的位置:"+index); //6第一次的位置:1 System.out.println("6最后一次出现的位置:"+lastindex); //6最后一次出现的位置:1 /* * toArray()将集合转换成的数组类型 */ Object[] obj = list.toArray(); int sum = 0; for (int i = 0; i < obj.length; i++) { sum = sum + ((Integer)obj[i]).intValue(); } System.out.println("所有元素的和为"+sum); //所有元素的和为33 //使用clear()方法清空List集合 list.clear(); System.out.println(list.size()); //0 } }
代码演示
package demo; import java.util.LinkedList; public class LinkedListDemo { public static void main(String[] args) { LinkedList<String> l = new LinkedList<String>(); l.add("A"); l.add("B"); l.add("C"); l.add("D"); l.add("E"); l.addFirst("A0"); l.addLast("F"); l.add(2, "A1"); System.out.println("链表里的内容是:"+l); l.remove(l.size()-1); //等价于 l.removeLast(); System.out.println("链表里的内容是:"+l); l.remove(0); //等价于 l.removeFirst(); System.out.println("链表里的内容是:"+l); l.remove(1); System.out.println("链表里的内容是:"+l); Object val = l.get(0); l.set(0, (String)val+"Changed"); System.out.println("链表里的内容是:"+l); } }
迭代器Iterator
集合框架中还提供了Iterator接口,专门用于集合的迭代输出,所谓的迭代,可以理解为循环的意思
代码演示:
package demo; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class CollectionDemo4 { public static void main(String[] args) { /* * Iterator:迭代器,是一个接口 * List集合中提供了获取iterator的实现类的方法 * 用于迭代(遍历)元素 */ List<String> list = new ArrayList<String>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); //用多态的形式 Iterator it = list.iterator(); /* * 迭代器的特点:先问再取 * it.hasNext():判断是否有下一个元素 * it.next():取出元素 */ //while循环是专门为迭代器设计的 //注意问一次取一次,避免出现异常 while(it.hasNext()){ Object obj = it.next(); if(obj.equals("b")){ it.remove(); } } System.out.println(list); } }
代码讲解:上述代码演示了Iterator的使用,迭代器的使用可以使用集合对象.iterator()方法取得Iterator it对象
使用while循环遍历,需要先it.hasNext()判断迭代器是否有内容,如果有则使用it.next()移动遍历内容。
当然迭代也可以加入泛型,我们来演示一下泛型类的使用,和泛型类的迭代
代码演示:
package demo; import java.util.ArrayList; import java.util.Iterator; import java.util.List; class Point<E,K>{ private E x; private K y; public Point() { } public Point(E x, K y) { super(); this.x = x; this.y = y; } public E getX() { return x; } public K getY() { return y; } public void setX(E x) { this.x = x; } public void setY(K y) { this.y = y; } public String toString(){ return "("+x+","+y+")"; } } public class TestPoint { public static void main(String[] args) { Point<Integer, Integer> p1 = new Point<Integer, Integer>(2, 2); Point<Integer, Integer> p2 = new Point<Integer, Integer>(3, 4); Point<Integer, Integer> p3 = new Point<Integer, Integer>(5, 2); List<Point<Integer, Integer>> list = new ArrayList<Point<Integer, Integer>>(); list.add(p1); list.add(p2); list.add(p3); Iterator<Point<Integer, Integer>> it = list.iterator(); while(it.hasNext()){ Point<Integer, Integer> p = (Point<Integer, Integer>)it.next(); System.out.println("点x坐标为"+p.getX()+",y坐标为"+p.getY()); } } }
foreach循环
for-each循环是一种高级的for循环,for-each循环可以遍历数组也可以遍历集合
代码演示:
package demo; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class ForecahDemo { public static void main(String[] args) { List<String> list = new ArrayList<String>(); list.add("one"); list.add("two"); list.add("three"); //使用toArray()将集合转换成数组 Object[] arr = list.toArray(); System.out.println(Arrays.toString(arr)); for (Object obj : arr) { System.out.println((String)obj); } /* * 将数组转换成集合 * Arrays工具类中提供了一个方法 * asList() * 转换后的集合不能增加和删除 * 要想接着操作,通过addAll操作,放进新的集合里 */ String[] arr3 = new String[]{"a","b","c"}; //将数组转换成集合对象 List<String> list3 = Arrays.asList(arr3); for (Object object : list3) { System.out.println(object+" "); } } }
使用for-each循环:
for(数组类型 变量名 或 数据类型 变量名 : 数组或集合对象){
执行语句;
}
for-each循环不需要写出结束条件,或者i的步长,for-each会自动遍历到数组尾或集合尾结束,即i<=a.length
比较器
有时候需要为多个对象排序时,必须设置排序规则,而排序规则就可以通过比较器进行设置,而在java之中比较器提供有两种:Comparable和Comparator;
Comparable:适合永久的比较规则,即实体类实现接口Comparable并重写compareTo方法
Comparator:适合突然需要的比较规则,不想去修改原来实体类,而定义的一种排序规则
Comparable代码演示:
1.创建实体类Point,并实现Comparable接口
package demo; public class Point implements Comparable<Point> { private int x; private int y; public Point(){ } public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public String toString() { return "Point [x=" + x + ", y=" + y + "]"; } //重写compareTo方法,定义排序规则 public int compareTo(Point o) { if((this.x*this.x+this.y*this.y)>(o.x*o.x+o.y+o.y)){ return 1; }else if((this.x*this.x+this.y*this.y)==(o.x*o.x+o.y+o.y)){ return 0; }else { return -1; } } }
2.编写测试类ComparablePointDemo,测试
package demo; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * @author 超级皮皮虾 * @description 永久比较用Comparable 临时用Comparator * */ public class ComparablePointDemo { public static void main(String[] args) { List<Point> p = new ArrayList<Point>(); p.add(new Point(1, 2)); p.add(new Point(1, 1)); p.add(new Point(2, 2)); System.out.println("没有排序前"+p); /* * 如果放进集合的元素想要排序,必须实现Comparable接口 * 实现里面的int CompareTo(Object obj)方法 * 当前元素与传进来的元素进行比较 * 当前元素大于传进来的元素,则返回>0 * 当前元素等于传进来的元素,则返回=0 * 当前元素小于传进来的元素,则返回<0 */ //使用Collections算法的sort(List list)方法进行排序 Collections.sort(p); System.out.println("使用排序后"+p); } }
代码结果:
没有排序前[Point [x=1, y=2], Point [x=1, y=1], Point [x=2, y=2]] 使用排序后[Point [x=1, y=1], Point [x=1, y=2], Point [x=2, y=2]]
Comparator代码演示:
1.创建实体类Point,并实现Comparable接口
package demo; public class Point implements Comparable<Point> { private int x; private int y; public Point(){ } public Point(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } public void setX(int x) { this.x = x; } public void setY(int y) { this.y = y; } public String toString() { return "Point [x=" + x + ", y=" + y + "]"; } //重写compareTo方法,定义排序规则 public int compareTo(Point o) { if((this.x*this.x+this.y*this.y)>(o.x*o.x+o.y+o.y)){ return 1; }else if((this.x*this.x+this.y*this.y)==(o.x*o.x+o.y+o.y)){ return 0; }else { return -1; } } }2.编写测试类ComparablePointDemo2,测试
package demo; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class ComparablePointDemo { public static void main(String[] args) { List<Point> p = new ArrayList<Point>(); p.add(new Point(1, 2)); p.add(new Point(1, 1)); p.add(new Point(2, 2)); System.out.println(p); /* 原来的Point不能变的情况,想临时改变排序规则 我们可以调用sort的重载方法 sort(Collection c,Comparator c): Comparator是比较器接口,需要重写接口里的compare(Object obj1,Object obj2) obj1> obj2 返回>0 obj1= obj2 返回=0 obj1< obj2 返回<0 */ //使用匿名内部类创建 Comparator<Point> my = new Comparator<Point>() { @Override public int compare(Point o1, Point o2) { return -(o1.getX()-o2.getX()); } }; Collections.sort(p, my); System.out.println(p); } }
代码结果:
[Point [x=1, y=2], Point [x=1, y=1], Point [x=2, y=2]] [Point [x=2, y=2], Point [x=1, y=2], Point [x=1, y=1]]
代码讲解:我们可以看到Point类原本实现了Comparable接口,并且完成comparaTo方法的重写,这时候向临时改变排序规则,就可以不需要修改Point类,使用匿名内部类的方法创建Comparator类的对象,并且实现compare方法,使用Collections.sort(List list,Comparator mycom)来进行排序