集合框架
Collection接口
Collection操作对象
Collection是集合框架的父接口,其中包含的方式是所有集合对象都可以调用的
下面演示的集合对象的基本API的操作:
package collection;
import java.util.ArrayList;
import java.util.Collection;
/**
* 通过集合操作对象
*
* @author Wildmess
*
*/
public class CollectionDemo2 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add(new Point(1,1));
c.add(new Point(2,2));
c.add(new Point(3,3));
c.add(new Point(4,4));
c.add(new Point(5,5));
System.out.println("这个集合目前已有的元素有:" + c);
/*
* boolean contains(E e)
* 判断当前集合是否包含给定的元素
*/
Point p = new Point(2, 2);
System.out.println("这个集合是否包含给出的对象:" + c.contains(p));
/*
* boolean remove()
* 删除当前集合里的指定元素
* 采用的是equals()方法比较,只要结果为true,就删去,
* 但equal()方法比较仅进行一次
*/
c.remove(new Point(3,3));
System.out.println("这个集合目前已有的元素有:" + c);
/*
* int size()
* 返回当前集合的元素个数
*/
System.out.println("这个集合的元素个数为:" + c.size());
/*
* boolean isEmpty()
* 判断集合是否为空
*/
System.out.println("这个集合是否为空:" + c.isEmpty());
c.clear();
System.out.println("这个集合目前已有的元素有:" + c);
System.out.println("这个集合是否为空:" + c.isEmpty());
}
}
Point实体类:
package cn.tedu.collection;
public class Point {
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public Point() {
super();
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
@Override
public String toString() {
return "Point (" + x + ", " + y + ")";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Point other = (Point) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
集合中元素保存对象的引用
集合中保存的是对象的引用,如图所示:
意思就是如果对p的x属性修改,会影响c对象中第一个元素的x属性,因为指向的是同一个对象
package collection;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo3 {
public static void main(String[] args) {
Collection c = new ArrayList();
Point p = new Point(1,1);
c.add(p);
System.out.println("p:" + p);
System.out.println("c:" + c);
//修改p对象中的x的值
p.setX(2);
System.out.println("p:" + p);
System.out.println("c:" + c);
}
}
集合中存放的是对象的引用
其它类型保存对象的方法
不同类型的对象赋值,会有不同的效果,如图:
package cn.tedu.collection;
import java.util.Arrays;
public class ValueDemo {
public static void main(String[] args) {
String s = "Hello";
int a=1;
Point p = new Point(1,2);
Point[] arr = {new Point(3,4),new Point(5,6),new Point(7,8)};
System.out.println("s:" + s);
System.out.println("a:" + a);
System.out.println("p:" + p);
System.out.println("arr:" + Arrays.toString(arr));
test(s,a,p,arr);
System.out.println("s:" + s);
System.out.println("a:" + a);
System.out.println("p:" + p);
System.out.println("arr:" + Arrays.toString(arr));
}
public static void test(String str,int n,Point p0,Point[] ps) {
//main中的s不会改变,因为修改的是str变量,是一个在常量堆中新生成的变量
str = str.substring(2);
//int传过来的是a的值,也不会收到影响
n++;
//main方法中的对象p会改变,因为test方法传过来的是p对象的引用,修改对象属性会改变main方法中的对象p
p0.setX(8);
//main方法中的对象数组arr[0]对象的属性会改变,因为其也是引用传递
ps[0].setX(5);
//数组中存的依然是对象类型,会改变
Point[] ps2 = Arrays.copyOf(ps, ps.length+1);
ps2[1].setX(8);
}
}
集合对集合的操作
一个集合对象还可以对另一个集合对象进行整体的操作,比如向一个集合中添加另一个集合的元素,或者删除它们
代码演示如下:
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Collection;
/**
* 演示集合对集合的操作
*
* @author Wildmess
*
*/
public class CollectionDemo4 {
public static void main(String[] args) {
Collection c1 = new ArrayList();
Collection c2 = new ArrayList();
c1.add("java");
c1.add("C");
c1.add("C#");
c1.add("php");
c1.add("web");
c2.add("java");
c2.add("web");
c2.add("C");
System.out.println(c1);
System.out.println(c2);
/*
* boolean addAll(Collection c)
* 将给定集合c1中的元素添加到集合c2中
* 添加后当前集合c2元素发生改变返回true,否则false
*/
System.out.println("将c1添加到c2中成功:" + c2.addAll(c1));
System.out.println(c2);
/*
* boolean containAll(Collection c)
* 判断当前集合是否包含给定集合中的所有元素
*/
Collection c3 = new ArrayList();
c3.add("java");
c3.add("web");
c3.add("C");
System.out.println(c3);
System.out.println("c3中的元素c2是否完全包含:" + c2.containsAll(c3));
/*
* boolean removeAll(E e)
* 删除指定集合中包含的所有此集合的元素
*/
System.out.println(c2);
System.out.println("是否在c2中包含的c3元素删去:" + c2.removeAll(c3));
System.out.println(c2);
}
}
迭代器
Collection 提供了用于遍历集合的方法:
Iterator iterator()
该方法会返回一个Iterator的实现类,称为迭代器
java.util.Iterator接口:迭代器接口
不同的集合实现类都提供了一个迭代器实现类用于遍历自身元素,因此,我们在遍历一个集合时只需要获取该迭代器遍历即可。迭代器规定了集合遍历元素的操作方式,循环三步:问,取,删,其中删除不是必须的。
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* 遍历集合元素
* 统一的遍历集合元素的操作,迭代器模式:
* Iterator iterator()
*
* 迭代器遍历集合遵循的原则是:问、取、(删)。
* @author Wildmess
*
*/
public class IteratorDemo {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("1");
c.add("#");
c.add("23");
c.add("#");
c.add("4");
c.add("#");
c.add("567");
c.add("#");
c.add("890");
System.out.println(c);
/*
* 迭代器遍历集合
*/
Iterator it = c.iterator();
/*
* 判断集合是否还有下一个元素可以迭代
*/
while(it.hasNext()) {
/*
* next()
* 获取集合的下一个元素
*/
// System.out.println(it.next());
String str = (String) it.next();
// System.out.println(str);
/*
* 获取到元素后,判断是否为”#“,如果是,就删除
* remove():删除最后一个元素
*/
if(str.equals("#")) {
it.remove();
} else {
System.out.println(str);
}
}
System.out.println(c);
}
}
增强for循环
使用迭代器遍历集合优点麻烦,有没有更好的办法呢?
JDK5之后推出了一个新特性:增强for循环也称为:新循环
新循环不取代传统for循环的工作,它只是用来遍历数组或集合使用的.
需要注意:新循环的语法是编译器认可而不是虚拟机.意思就是编译时就会变成上面Iterator的代码,然后被编译到class文件中
遍历数组
package cn.tedu.collection;
/**
* 增强for循环
* 也称新循环,foreach
* 用来遍历集合或者数组使用的
*
* @author Wildmess
*
*/
public class NewForArray {
public static void main(String[] args) {
String[] array = {"1","234","567","89","0"};
//传统for循环
for(int i=0; i<array.length; i++) {
System.out.println(array[i]);
}
//新循环
for(String str: array) {
System.out.println(str);
}
}
}
遍历集合
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Collection;
/**
* 新循环遍历集合
* @author Wildmess
*
*/
public class NewForArray2 {
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("12");
c.add("3");
c.add("45");
c.add("678");
System.out.println(c);
/*
* 编译器会将新循环遍历集合改成迭代器遍历
* 所有遍历的过程中不能通过集合的方法增删元素
* 增删就不要使用增强for循环
*/
for(Object o:c) {
System.out.println(o);
}
}
}
泛型集合
JDK5推出时推出的特性
泛型又称为参数化类型,允许我们在使用一个类的时候指定它当中的属性,方法的参数,返回值的类型,使得我们使用起来更灵活.
泛型在集合中广泛使用,用于在使用集合时规定该集合的元素类型.
泛型的默认类型为Object.
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class TypeDemo {
public static void main(String[] args) {
//泛型规定了集合的元素类型
Collection<String> c = new ArrayList<String>();
/*
* 编译器会检查实际参数的类型与泛型指定
* 的类型是否匹配,不匹配编译不通过
*/
c.add("12");
c.add("3");
c.add("45");
c.add("678");
System.out.println(c);
//获取元素时也不需要再造型
for(String str: c) {
System.out.println(str);
}
System.out.println("____________________________");
/*
* 存整数int时,
* 泛型关键字为Integer
*/
Collection<Integer> c2 = new ArrayList<Integer>();
c2.add(12);
c2.add(3);
c2.add(45);
c2.add(678);
System.out.println(c2);
for(Integer n: c2) {
System.out.println(n);
}
System.out.println("____________________________");
/*
* 指定迭代器,不屑泛型也有警告,所以我们要指定类型
* 而且类型要和集合一样
*/
Iterator<Integer> it = c2.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
LIst接口
List集合可以存放重复元素,并且有序,其特点是提供了一组通过下标操作元素的方法。
- java.util.ArrayList:内部由数组实现,查询效率更好,但是增删效率差.
- java.util.LinkedList:内部由链表实现,增删效率好,尤其首尾增删元素.但是查询效率差.在性能
不是非常苛刻要求的前提下,通常使用ArrayList
List集合基本操作
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.List;
/**
* java.util.List 线性表
*
* @author Wildmess
*
*/
public class ListDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("12"); //0
list.add("345"); //1
list.add("67"); //2
list.add("89"); //3
list.add("0"); //4
System.out.println(list);
/*
* E get(int index)
* 获得指定下标处对应的元素
*
* 得到下标为2的元素
*/
System.out.println(list.get(2));
/*
* E set(int index,E e)
* 替换指定下标处对应的元素
*
* 替换下标为3的元素
*/
list.set(3, "123");
System.out.println(list);
/*
* list集合也可以使用普通的for循环遍历
*/
String str = null;
for(int i=0; i<list.size(); i++) {
str = list.get(i);
System.out.println(str);
}
}
}
List集合插入删除元素
下面代码演示如何向集合中间位置插入或删除元素:
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.List;
/**
* List重载了add()和remove()方法支持使用下标操作元素
*
* @author Wildmess
*
*/
public class ListDemo2 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("12"); //0
list.add("345"); //1
list.add("67"); //2
list.add("89"); //3
list.add("0"); //4
System.out.println(list);
/*
* void add(int index,E e)
* 向指定的位置插入指定的元素
*/
list.add(2, "abc");
System.out.println(list);
/*
* remove(int index)
* 删除指定下标处对应的元素
*/
list.remove(3);
System.out.println(list);
}
}
List集合截取子集合
一个集合可能需要截取出其中的一个部分:
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.List;
/**
* 取子集
* List subList(int start,int end)
* List可以获取指定范围内的子集
*
* @author Wildmess
*
*/
public class ListDemo3 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for(int i=0;i<10;i++) {
list.add(i);
}
System.out.println("list:" + list);
//获取3~7这部分
List<Integer> subList = new ArrayList<Integer>();
subList = list.subList(3, 7);
System.out.println("subList:" + subList);
//将数组中的每个元素扩大10倍
for(int i=0;i<subList.size();i++) {
subList.set(i, subList.get(i)*10);
}
System.out.println("subList:" + subList);
/*
* 对子集元素的操作就是对原集合对应元素的操作
*/
System.out.println("list:" + list);
//删除2~8
list.subList(2, 9).clear();
System.out.println("list:" + list);
}
}
List集合转数组
当我们拥有一个集合对象时,有时可能需要将它转换为数组:
package cn.tedu.collection;
/**
* 集合转换为数组
* Collection提供了一个方法:toArray,可以将当前集合转换为一个数组
*
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
public class CollectionToArrayDemo {
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
c.add("12");
c.add("345");
c.add("67");
c.add("89");
c.add("0");
System.out.println(c);
// Object[] arr = c.toArray();
/*
* 常用,可以传入一个指定类型的数组,该数组的元素类型
* 应该与集合中的元素类型一致
*
* 返回值则是转换后的数组,该数组会保存集合中所有的元素
* 如果长度超出集合的长度,则自动用默认值填充
* 如果长度不够,则自动创建新数组,长度和集合元素个数相等
*
*/
// String[] array = c.toArray(new String[1]);
// String[] array = c.toArray(new String[10]);
String[] array = c.toArray(new String[c.size()]);
System.out.println(Arrays.deepToString(array));
}
}
数组转LIst集合
相反,有时我们会将数组转换为集合:
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 数组转集合
*
* @author Wildmess
*
*/
public class ArrayToListDemo {
public static void main(String[] args) {
String[] str = {"abc","def","g","hi","jkl"};
//数组转集合
List<String> list = Arrays.asList(str);
System.out.println("str数组:" + Arrays.toString(str));
System.out.println("list集合:" + list);
//对集合的操作就是对源数组的操作
//即对集合中元素属性的更改,会影响原来数组中的元素属性
list.set(3,"qwe");
System.out.println("修改后的str数组:" + Arrays.toString(str));
System.out.println("修改后的list集合:" + list);
/*
* 这里就不能对集合中的元素进行增删
* 因为数组是定长
*
* 如果真的进行了会报异常
*/
// list.add("qtyu");
// list.remove(2);
//想进行增删的话,就要创建新的集合
List<String> list2 = new ArrayList<String>();
list2.addAll(list);
System.out.println("list2:" + list2);
list2.add("gbvn");
System.out.println("修改后的List2:" + list2);
}
}
集合排序
自然排序
数组中可以使用Arrays.sort()方法为数值元素排序,List集合中也有类似的操作:
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* 排序List集合
* 集合工具类:java.util.Collections提供了很多静态方法用于操作集合,
* 其中sort方法是用来对List集合进行从小到大自然排序的
*
* @author Wildmess
*
*/
public class SortListDemo1 {
public static void main(String[] args) {
Random random = new Random();
int[] s = new int[10];
for(int i=0;i<10;i++) {
s[i] = random.nextInt(100);
}
System.out.println("数组排序前:" + Arrays.toString(s));
Arrays.sort(s);
System.out.println("数组排序后:" + Arrays.toString(s));
List<Integer> list = new ArrayList<Integer>();
for(int i=0;i<10;i++) {
list.add(random.nextInt(100));
}
System.out.println("集合排序前:" + list);
Collections.sort(list);
System.out.println("集合排序后:" + list);
}
}
自定义排序规则
如果集合中的元素不是数值类型,而是对象,那我们要怎么排序呢?
Collections的sort方法再排序集合时要求集合元素必须实现Comparable接口,否则编译不通过
由于该方法要求集合元素必须实现该接口,这对于我们排序自定义元素而言就有了 侵入性 ,不利于代码维护。
一
为了实现自定义规则排序,还能不入侵当前类,我们可以通过编写一个Comparator对象来自定义排序规则:
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
public class SortListDemo2 {
public static void main(String[] args) {
Random random = new Random();
List<Point> list = new ArrayList<Point>();
for(int i=0; i<10; i++) {
list.add(new Point(random.nextInt(10),random.nextInt(10)));
}
System.out.println("list:" + list);
Comparator<Point> comparator = new Comparator<Point>() {
/*
* comparator方法用来定义参数p1和p2的比较大小规则
*
* 返回值>0表示:p1>p2
* 返回值<0表示:p1<p2
* 返回值=0表示:p1==p2
*
* 比较list集合中点离零点(0,0)的距离
*/
@Override
public int compare(Point p1, Point p2) {
int len1 = p1.getX()*p1.getX()+p1.getY()*p1.getY();
int len2 = p2.getX()*p2.getX()+p2.getY()*p2.getY();
return len1-len2;
}
};
/*
* 重载的sort方法要求再传入一个参数
* 是Comparator接口的实现类
* 该接口用来单独定义一个比较器,为集合元素指定比较大小的规则
*/
Collections.sort(list, comparator);
System.out.println("list:" + list);
}
}
二
还可以自定义实现其他类型的对象比较:
package cn.tedu.collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* 比较器编写常用类型的其他规则
*
* @author Wildmess
*
*/
public class SortListDemo3 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("赵一一");
list.add("孙二");
list.add("李三民");
list.add("钱");
System.out.println("list:" + list);
Comparator<String> com = new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return s1.length()-s2.length();
}
};
Collections.sort(list,com);
System.out.println("list:" + list);
}
}
数据结构概述
队列
经典的数据结构之一,特点是遵循先进先出的规则
java.util.Queue接口是队列的接口,规定了队列出入队的相关方法,其继承自Collection:
package cn.tedu.collection;
import java.util.LinkedList;
import java.util.Queue;
/**
* 队列
*
* 队列的常用实现类是LinkedList
* @author Wildmess
*
*/
public class QueueDemo {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
/*
* offer:入队
* add方法也可以用
*/
queue.offer(1);
queue.offer(2);
queue.offer(3);
queue.offer(4);
queue.offer(5);
System.out.println("queue:" + queue);
/*
* poll:出队
*/
Integer n = queue.poll();
System.out.println("n:" + n);
System.out.println("queue:" + queue);
/*
* peek:引用队首元素
* 获取队首元素,但不删除
*/
Integer i = queue.peek();
System.out.println("i:" + i);
System.out.println("queue:" + queue);
/*
* 可以使用迭代器遍历队列
* 其不会出队队列中的元素
*/
for(Integer a : queue) {
System.out.println("a:" + a);
}
System.out.println("queue:" + queue);
/*
* Collection中定义的方法都可以用
*/
int size = queue.size();
System.out.println("size:" + size);
/*
* 使用poll方法遍历队列元素
*/
while(queue.size()>0) {
Integer j = queue.poll();
System.out.println("j:" + j);
}
System.out.println("queue:" + queue);
}
}
双向队列
package cn.tedu.collection;
import java.util.Deque;
import java.util.LinkedList;
/**
* 双向队列
* 队列俩边都可以进行入队、出队操作的队列
*
* 常用实体类:LinkedList
*
* @author Wildmess
*
*/
public class DequeDemo {
public static void main(String[] args) {
Deque<Integer> deque = new LinkedList<Integer>();
deque.offer(1);
deque.offer(2);
deque.offer(3);
System.out.println("deque:" + deque);
//队首入队
deque.offerFirst(0);
System.out.println("deque:" + deque);
//队尾入队(等价于offer、add)
deque.offerLast(4);
System.out.println("deque:" + deque);
//队首出队
Integer i = deque.pollFirst();
System.out.println("deque:" + deque);
//队尾出队
i= deque.pollLast();
System.out.println("deque:" + deque);
//获取队首元素
Integer start = deque.peekFirst();
System.out.println("deque.start:" + start);
//获取队尾元素
Integer end = deque.peekLast();
System.out.println("deque.end:" + end);
System.out.println(deque);
}
}
栈
经典的数据结构之一,特点是遵循先进后出的规则
package cn.tedu.collection;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Stack;
/**
* 栈
*
* @author Wildmess
*
*/
public class StackDemo {
public static void main(String[] args) {
Deque<Integer> stack = new LinkedList<>();
//入队
System.out.println("push:");
stack.push(1);
stack.push(2);
stack.push(3);
System.out.println("stack:" + stack);
//出队
System.out.println("pop:");
Integer e = stack.pop();
System.out.println("e:" + e);
System.out.println("stack:" + stack);
//获取顶层元素,但不移出
System.out.println("peek:");
Integer top = stack.peek();
System.out.println("top:" + top);
System.out.println("stack:" + stack);
//迭代器遍历
for(Integer i : stack) {
System.out.println(i);
}
System.out.println("stack:" + stack);
for(int i=0; i<=stack.size();i++) {
Integer a = stack.pop();
System.out.println(a);
}
System.out.println("stack:" + stack);
}
}