集合框架
什么是集合
集合与数组一样,可以保存一组元素,并且提供了操作元素的相关方法,使用更方便.
java集合框架中相关接口
java.util.Collection接口:
java.util.Collection是所有集合的顶级接口.Collection下面有多种实现类,因此我们有更多的数据结构可供选择.
Collection下面有两个常见的子接口:
- java.util.List:线性表.是可重复集合,并且有序.
- java.util.Set:不可重复的集合,大部分实现类是无序的.
这里可重复指的是集合中的元素是否可以重复,而判定重复元素的标准是依靠元素自身equals比较的结果.为true就认为是重复元素.
//集合只能存放引用类型元素
Collection c = new ArrayList();
//添加元素 boolean add(E e),向当前集合中添加一个元素.当元素成功添加后返回true
c.add("1");
c.add("2");
System.out.println(c);
//int size()返回当前集合的元素个数
int size = c.size();
System.out.println(size);
//boolean isEmpty() 判断当前集合是否为空集(不含有任何元素)
boolean isEmpty = c.isEmpty();
System.out.println(isEmpty);
//清空集合
c.clear();
System.out.println(c);
System.out.println(c.size());
System.out.println(c.isEmpty());
集合与元素equals方法相关的方法
//需要新建一个类的实例作为测试,这里用的是point类,里面有int型的x,y,及相关方法
//集合受equals方法影响的操作
Collection c = new ArrayList();
//如果没有重写toString,会导致输出为地址,显示不直观,加上后会正常显示
c.add(new Point(1,2));
c.add(new Point(3,4));
c.add(new Point(5,6));
System.out.println(c);
//boolean contains(Object o),判断当前集合是否包含给定元素,这里判断的
// 依据是给定元素是否与集合现有元素存在equals比较为true的情况。
Point p = new Point(1,2);
boolean contains = c.contains(p);
//重写equals前以为没有添加显示为不包含,重写后则可能会显示为ture
System.out.println("集合是否为包含元素"+contains);
//remove用来从集合中删除给定元素,删除的也是与集合中equals比较为true的元素。
// 注意,对于可以存放重复元素的集合而言,只删除一次。
c.remove(p);
System.out.println(c);
集合存放的是元素的引用
集合只能存放引用类型元素,并且存放的是元素的引用
Collection c = new ArrayList();
Point p = new Point(1,2);
c.add(p);
System.out.println("p:"+p);//p:(1,2)
System.out.println("c:"+c);//c:[(1,2)]
p.setX(2);
System.out.println("p:"+p);//p:(2,2)
System.out.println("c:"+c);//c:[(2,2)]
集合间的操作
集合提供了如取并集,删交集,判断包含子集等操作
//Collection c1 = new ArrayList();
Collection c1 = new HashSet();//不可重复元素
c1.add("java");
c1.add("c");
c1.add("c++");
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
boolean tf = c1.addAll(c2);
System.out.println(tf);
System.out.println("c1:"+c1);
System.out.println("c2:"+c2);
Collection c3 = new ArrayList();
c3.add("ios");
c3.add("c++");
c3.add("php");
System.out.println("c3:"+c3);
//boolean containsAll(Collection c)判断当前集合是否包含给定集合中的所有元素
boolean contains = c1.containsAll(c3);
System.out.println("包含所有元素:"+contains);
//boolean removeAll(Collection c)删除当前集合中与给定集合中的共有元素
c1.removeAll(c3);
System.out.println("c1:"+c1);
System.out.println("c3:"+c3);
集合的遍历
Collection提供了统一的遍历集合方式:迭代器模式
对应的方法:Iterator iterator()
该方法会获取一个用于遍历当前集合元素的迭代器.
java.util.Iterator接口
迭代器接口,定义了迭代器遍历集合的相关操作.
不同的集合都实现了一个用于遍历自身元素的迭代器实现类,我们无需记住它们的名字,用多态的角度把他们看做为Iterator即可.
迭代器遍历集合遵循的步骤为:问,取,删.其中删除元素不是必要操作
Collection c = new ArrayList();
c.add("1");
c.add("2");
c.add("3");
c.add("4");
c.add("5");
System.out.println(c);
//boolean hasNext() 判断集合是否还有元素可以遍历
Iterator it = c.iterator();
//E next() 获取集合下一个元素(第一次调用时就是获取第一个元素,以此类推)
while(it.hasNext()){
String str = (String)it.next();
System.out.println(str);
}
System.out.println(c);
迭代器遍历过程中不得通过集合的方法增删元素
Collection c = new ArrayList();
c.add("1");
c.add("#");
c.add("2");
c.add("#");
c.add("3");
c.add("#");
c.add("4");
c.add("#");
c.add("5");
System.out.println(c);
//boolean hasNext() 判断集合是否还有元素可以遍历
Iterator it = c.iterator();
//E next() 获取集合下一个元素(第一次调用时就是获取第一个元素,以此类推)
while(it.hasNext()){
String str = (String)it.next();
System.out.println(str);
if ("#".equals(str)){
//c.remove(str);迭代器的remove方法可以将通过next方法获取的元素从集合中删除。
//迭代器要求遍历的过程中不得通过集合的方法增删元素,
// 否则会抛出异常:ConcurrentModificationException
it.remove();
}
}
System.out.println(c);
增强型for循环
JDK5之后推出了一个特性:增强型for循环
-
也称为新循环,使得我们可以使用相同的语法遍历集合或数组.
-
注意:新循环并不取代传统的for循环,只是用来遍历数组
-
语法:for(元素类型 变量名 : 集合或数组){循环体}
String[] array = {"1","2","3","4","5",}; for (String str : array){ System.out.println(str); } Collection c = new ArrayList(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); //迭代器遍历 Iterator it = c.iterator(); while(it.hasNext()){ String str = (String)it.next(); System.out.println(str); } //新循环遍历 for(Object o : c){ String str = (String)o; System.out.println(str); }
泛型
JDK5之后推出的另一个特性:泛型
泛型也称为参数化类型,允许我们在使用一个类时指定它当中属性,方法参数或返回值的类型.
-
泛型在集合中被广泛使用,用来指定集合中的元素类型.
-
有泛型支持的类在使用时若不指定泛型的具体类型则默认为原型Object
//添加泛型后可以省略掉增强for循环中的转换造型,简化代码 Collection<String> c = new ArrayList<>(); c.add("one"); c.add("two"); c.add("three"); c.add("four"); c.add("five"); for(Object o : c){ System.out.println(o); } //遍历集合时会被改成迭代器遍历,因此便利的过程中不要通过集合的方法增删元素,要使用迭代器进行操作 //迭代器遍历 Iterator<String> it = c.iterator(); while(it.hasNext()){ String str = it.next();//获取元素时无需再造型 System.out.println(str); }
List集
java.util.List接口,继承自Collection.
List集合是可重复集,并且有序,提供了一套可以通过下标操作元素的方法
常用实现类:
- java.util.ArrayList:内部使用数组实现,查询性能更好.
- java.util.LinkedList:内部使用链表实现,首尾增删元素性能更好.
- 在对性能没有特别苛刻的情况下,通常使用ArrayList
List集合常见方法
注:下面的方法是List集合的独有的方法
get()与set()
List集合的特点是:可以存放重复元素,并且有序。其提供了一套可以通过下标操作元素的方法
List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
list.add("four");
list.add("five");
System.out.println(list);
//E get(int index) 获取指定下标对应的元素
String e = list.get(2);//获取第三个元素
System.out.println(e);
//E set(int index,E e) 将给定元素设置到指定位置,返回值为该位置原有的元素。
//替换元素操作
String old = list.set(1,"six");
System.out.println(list);
System.out.println("被替换的元素是:"+old);
重载的add()和remove()
List集合提供了一对重载的add,remove方法
//void add(int index,E e) 将给定元素e插入到指定位置,后面元素向后移一位
list.add(2,"seven");
System.out.println(list);
//E remove(int index) 删除并返回指定位置上的元素
String e = list.remove(1);
System.out.println(list);
System.out.println("被删除的元素:"+e);
subList()方法
List subList(int start,int end) 获取当前集合中指定范围内的子集。两个参数为开始与结束的下标(含头不含尾)
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
System.out.println(list);
//获取其中的2-5部分
List<Integer> sub = list.subList(2,6);
System.out.println(sub);
//将子集的元素扩大10倍
for (int i = 0; i < sub.size(); i++) {
sub.set(i, sub.get(i)*10);
}
System.out.println(sub);
//对子集的操作就是对原集合的操作,输出后发现list集合也会发生变化
System.out.println(list);
//删除操作(同样是含头不含尾)
list.subList(2,8).clear();
System.out.println(list);
集合与数组的转换
集合转换为数组
Collection提供了一个方法:toArray,可以将当前集合转换为一个数组
重载的toArray方法要求传入一个数组,内部会将集合所有元素存入该数组后将其返回(前提是该数组长度>=集合的size)。如果给定的数组长度不足,则方法内部会自行根据给定数组类型创建一个与集合size一致长度的数组并将集合元素存入后返回。
Collection<String> c = new ArrayList<>();
c.add("1");
c.add("2");
c.add("3");
c.add("4");
c.add("5");
System.out.println(c);
//将集合转为数组,该方法需要传入相应的长度
//如果前面是ArrayList<>(),长度建议给0
// String[] array = c.toArray(new String[c.size()]);
String[] array = c.toArray(new String[0]);
System.out.println(Arrays.toString(array));
数组转为list集合
数组的工具类Arrays提供了一个静态方法asList,可以将一个数组转换为List集合
String[] array = {"1","2","3","4","5"};
//因为直接输出数组为地址,所以需要加toString
System.out.println(Arrays.toString(array));
List<String> list = Arrays.asList(array);
System.out.println(list);
//对集合的操作就是对数组的操作,所以不能进行增删操作,及修改数组长度,否则将会发生 UnsupportedOperationException异常
list.add(3,"six");
System.out.println(list);
System.out.println(Arrays.toString(array));//会报错
//所以若希望对集合进行增删操作,需要新建一个集合并将相应的元素复制到新集合中
//集合是支持传入集合的,所以可以将之前的集合直接传入新建的集合中,在进行操作就可以了
List list2 = new ArrayList(list);
System.out.println(list2);
list2.add("9");
System.out.println(list2);
集合的排序
对list集合的排序:java.util.Collections是集合的工具类,里面提供了很多的静态方法便于我们进行操作,其中有一个静态方法sort可以对List集合进行自然排序
JDK8后List自身也提供了sort方法,效果相同
List<Integer> list = new ArrayList<>();
//生成随机数方法
Random ran = new Random();
for (int i = 0; i < 10; i++) {
//随机生成十个数
list.add(ran.nextInt(100));
}
System.out.println(list);
//进行排序,默认为由小到大
Collections.sort(list);
System.out.println(list);
使用该sort方法排序List集合时有一个前提条件:集合元素必须实现了Comparable可比较接口,sort方法会利用该接口上定义的抽象方法来对元素两两比较从而得知大小后进行排序。
因此元素没有实现该接口则编译不通过。
//新建一个point测试类,里面有x,y两个属性及相关方法
List<Point> list = new ArrayList<>();
list.add(new Point(1,2));
list.add(new Point(4,8));
list.add(new Point(7,6));
list.add(new Point(24,65));
list.add(new Point(24,25));
System.out.println(list);
Collections.sort(list);//编译不通过,
该操作具有侵入性:当我们使用一个API时,如果该API反过来要求我们的程序为其修改其它额外地方的代码,那么就具有了侵入性,这不利于我们程序的后期维护。
//新建一个point测试类,里面有x,y两个属性及相关方法
List<Point> list = new ArrayList<>();
list.add(new Point(25,2));
list.add(new Point(4,8));
list.add(new Point(7,6));
list.add(new Point(24,65));
list.add(new Point(24,25));
System.out.println(list);
//sort可以自己自己定义相应的比较方法,将自定义的比较方法传入就好了
Comparator<Point> c = new Comparator<Point>() {
@Override
public int compare(Point o1, Point o2) {
int len1 = o1.getX()* o1.getX()+o1.getY()* o1.getY();
int len2 = o2.getX()* o2.getX()+o2.getY()* o2.getY();
return len1-len2;
//如果从大到小排的话将定义的大小反过来就好了
//return len2-len1;
}
};
Collections.sort(list,c);
System.out.println(list);
当元素已经实现了Comparable接口,但是比较规则不满足排序需求时,依然可以提供额外比较规则
//默认的英文字符是按照Unicode编码进行排序
List<String> list = new ArrayList<>();
list.add("one");
list.add("Two");
list.add("nick");
list.add("seven");
System.out.println(list);
Collections.sort(list);
System.out.println(list);
//如果是中文的话仍需要自己再定义一个比较器进行比较排序
//例如按照字符多少排序
List<String> list = new ArrayList<>();
list.add("帅");
list.add("将军");
list.add("大将军");
list.add("摸金校尉");
Collections.sort(list,(o1,o2)->o1.length()-o2.length());
//JDK8之后可以用List自身提供的sort方法使用指定比较器排序元素
//也可以写为 list.sort((o1,o2)->o1.length()-o2.length());
System.out.println(list);