解决程序运行时需要创建新对象,在程序运行前不知道运行的所需的对象数量甚至是类型的问题。
Java中提供了一套集合类来解决这些问题包括:List、Set、Queue、Map
Collection:独立的元素序列,都服从一条或多条的规则
Map:成对的“键对值”对象,允许使用键来查找值
Array.asList()
方法:
该方法接受一个数组或用逗号隔开的元素列表,并转换为一个List对象。
Collection.addAll()
方法:
接受一个Collection对象,可以使用Array.asList()
产生Collection对象。
Collecions.addAll()
方法:
接受一个Collection对象,以及数组或者逗号隔开的元素列表,并将元素添加到Collection对象中。
Collection()
构造器方法:
Collection构造器方法接受一个Collection对象用于自身初始化。
public class TestAddObj {
public static void main(String[] args) {
Collection<Integer> collection = new ArrayList<>(Arrays.asList(1,2,3,4,8));// 构造器添加元素
Integer[] moreInts = {7,5,6};
collection.addAll(Arrays.asList(moreInts)); //Collection对象addAll()方法添加元素
Collections.addAll(collection,9,10,11,12);//Collections类addAll方法添加元素
Collections.addAll(collection,moreInts);//以Collection对象添加元素
for (int i: collection) {
System.out.print(i+"\t");//打印元素
}
List<Integer> list = Arrays.asList(1,2,3,6); //直接使用Array.asList方法添加
// list.add(3); // 报错,使用该方法产生的List本质上数组,不能修改大小,即不能适应add方法添加元素或delete方法删除元素
list.set(2,10);
System.out.println();
for (int i: list) {
System.out.print(i+"\t");
}
}
}
使用打印默认的打印行为(容器提供的toString
()方法
public class TestPrintContainers {
public static void main(String[] args) {
System.out.println(fill(new ArrayList<>()));
System.out.println(fill(new LinkedList<>()));
System.out.println(fill(new HashSet<>()));
System.out.println(fill(new TreeSet<>()));
System.out.println(fill(new LinkedHashSet<>()));
System.out.println(fill(new TreeMap<>()));
System.out.println(fill(new HashMap<>()));
System.out.println(fill(new LinkedHashMap<>()));
}
static Collection<String> fill(Collection<String> collection){
collection.addAll(Arrays.asList("rat","cat","dog"));//使用Collection对象作为参数添加一组元素
return collection;
}
static Map<String,String> fill(Map<String,String> map){
map.put("rat","Fuzzy");
map.put("cat","Rags");//put<key,value>添加键值 get(key)获取键的值
map.put("dog","Bosco");
map.put("dog","Spot");
return map;
}
}
List接口在Collection接口的基础上添加了大量的方法,使得可以在List中间插入和移除元素
List接口的实现类
ArrayList
长于随机访问元素,在其中插入和移除元素时较慢
LinkedList
随机访问较慢,可以较低代价的在List中间插入和移除元素
public class testList {
public static void main(String[] args) {
Random rand = new Random(100);
ArrayList
System.out.println("1: "+pets);
Pet lola = new Pet("lola");pets.add(lola);//add(obj) 列表最后插入obj
System.out.println("2: "+pets);
System.out.println("3: "+pets.contains(lola));// contains()判断是否包含
pets.remove(lola); //remove(obj)删除列表中的对obj象
Pet p = pets.get(2); //get(Index)获取索引位置对象
System.out.println("4: "+p+" "+pets.indexOf(p));//indexOf(obj)获取obj对象的位置
Pet milo = new Pet("Milo");
pets.add(milo);
System.out.println("5: "+ pets.indexOf(milo));
System.out.println("6: "+ pets.remove(milo));
System.out.println("7: "+pets.remove(p));
System.out.println("8: "+pets);
pets.add(3,new Pet("Jack"));//add(index,obj)将obj插入到index位置
System.out.println("9: "+pets);
List<Pet> sub = pets.subList(1,4);//sub(start,end)获取[start,end)列表片段
System.out.println("10: sub list [1,4) "+sub);
System.out.println("11: "+ pets.containsAll(sub));//containsAll(listObj)判断是否包含listObj的全部对象(忽略顺序)
Collections.sort(sub);//Collections.sort(list)对列表list进行排序(需要list包含的对象实现泛型接口Comparable<>)
System.out.println("12: sorted sub "+ sub);
System.out.println("13: "+ pets.containsAll(sub));
Collections.shuffle(sub,rand);//Collections.shuffle(list,rand)将list按rand规则打乱
System.out.println("14: shuffle sublist "+sub);
System.out.println("15: "+pets.containsAll(sub));
List<Pet> copy = new ArrayList<>(pets);
sub = Arrays.asList(pets.get(1),pets.get(4));//获取pets的第一个和第4个对象,返回一个列表,传入sub
System.out.println("16: sub: "+sub);
copy.retainAll(sub);//retainAll(list)与list所有元素取交集
System.out.println("17: "+copy);
copy = new ArrayList<>(pets);//构造器传参,初始化list
System.out.println(copy);
copy.remove(2);//remove(index)移除index位置对象
System.out.println("18: "+copy);
copy.removeAll(sub);//removeAll(list)与list取差集,移除list中包含的元素
System.out.println("19: "+copy);
copy.set(1,new Pet("Toby"));//set(index,obj)将index位置元素替换成obj
System.out.println("20: "+copy);
copy.addAll(2,sub);//add(index,list)将list所有元素插入到index位置
System.out.println("21: "+copy);
System.out.println("22: "+copy.isEmpty());//isEmpty()判断是否非空
copy.clear();//clear()移除所有元素
System.out.println("23: "+ copy.isEmpty());
pets.addAll(Pets.namePets(4));
System.out.println("24: "+pets);
Object[] o = pets.toArray();//toArray()转为数组
System.out.println("25: "+ o[3]);
Pet[] pas = pets.toArray(new Pet[0]);//toArray(T[])T[]为数组设置初始值
System.out.println("26: "+ pas[3].name);
}
}
class Pets{
static ArrayList
String[] names = new String[]{"Charlie","Max", "Buddy","Oscar",
"Milo","Bella","Molly"," Coco" ,"Ruby" ,"Lucy"};
Random random = new Random();
ArrayList
for (int j = 0; j < i; j++) {
pets.add(new Pet(names[j]));
}
return pets;
}
}
class Pet implements Comparable<Pet>{//继承泛型实现sort方法
public Pet(String name) {
this.name = name;
}
String name;@Override
public String toString() {//重写toString方法实现打印
return this.name;
}
@Override
public int compareTo(Pet anotherPet) {//实现Comparable接口
return this.name.compareTo(anotherPet.name);
}
}
迭代器是一个用于遍历并选择一个容器中元素的对象,而不必关心容器中的元素的底层结构。
Java中使用Iterator
来表示迭代器对象
使用iterator
方法要求容器返回一个迭代器。Iterator将准备好返回序列的第一个元素
next()
方法返回序列的下一个元素
hasNext()
检查是否还有下一个元素
remove()
移除序列最新返回的元素
public class TestIterator {
public static void main(String[] args) {
ArrayList
System.out.println(pets);
Iterator
while (petIterator.hasNext()){//判断
Pet p = petIterator.next();//返回下一个元素
System.out.print(p+"\t");
}
System.out.println();
for (Pet p: pets) { //通过Iterator实现的forEach循环遍历 本质上还是是Iterator
System.out.print(p+"\t");
}
petIterator = pets.iterator();
for (int i = 0; i < 4; i++) {
petIterator.next();//返回下一个元素(头部开始)
petIterator.remove();//移除next()方法返回的元素,使用该方法必须先使用next()方法
}
System.out.println();
System.out.println(pets);
}
}
使用迭代器时,不必关心序列底层结构,统一了对容器的访问方式
public class TestIterator1 {
public static void displayContainer(Iterator<Pet> petIterator){
while (petIterator.hasNext()){
Pet p = petIterator.next();
System.out.print(p+"\t");
}
System.out.println();
}
public static void main(String[] args) {
ArrayList<Pet> pets= Pets.namePets(6);
LinkedList<Pet> petsLL = new LinkedList<>(pets);
HashSet<Pet> petsHS = new HashSet<>(pets);
TreeSet<Pet> petsTS = new TreeSet<>(pets);
displayContainer(pets.iterator());
displayContainer(petsLL.iterator()); //迭代器能够访问不同的容器
displayContainer(petsHS.iterator());
displayContainer(petsTS.iterator());
}
}
List类的专用迭代器ListIterator
ListIterator
添加了previous
方法和hasPrevious
方法实现了对前一个元素的访问以及存在性判断;
添加了set
方法替换访问过的最后一个元素
public class TestListIterator {
public static void main(String[] args) {
List<Pet>pets = Pets.namePets(7);
ListIterator<Pet> petListIterator = pets.listIterator();
while (petListIterator.hasNext()){
System.out.print(petListIterator.next()+"\t");
}
System.out.println();
while (petListIterator.hasPrevious()){
System.out.print(petListIterator.previous()+"\t");//前移动访问
}
System.out.println();
petListIterator.next();
petListIterator.set(new Pet("Scout"));//将第一个元素替换
System.out.println(pets);
}
}
LinkedList
与ArrayList
一样实现了基本的List接口,它在中间插入更加高效,在随机访问上要慢一些
LinkedList
还添加了作为栈、队列双端队列的方法
public class TestLinkedList {
public static void main(String[] args) {
LinkedList<Pet> pets = new LinkedList<>(Pets.namePets(8));
System.out.println(pets);
//获取头部元素,前面二者完全相同,当为空时抛出NoSuchElementException,peek()方法返回null
System.out.println("pets.getFirst(): "+pets.getFirst());
System.out.println("pets.element(): "+pets.element());
System.out.println("pets.peek(): "+pets.peek());
//移除头部元素,前面二者完全相同,当为空时抛出NoSuchElementException,poll()方法返回null
System.out.println("pets.remove(): "+pets.remove());
System.out.println("pets.removeFirst(): "+pets.removeFirst());
System.out.println("pets.poll(): "+pets.poll());
//头部插入
pets.addFirst(new Pet("Ollie"));
System.out.println("After addFirst: "+pets);
//尾部插入
pets.offer(Pets.randomPet());
System.out.println("After offer: "+pets);
pets.add(Pets.randomPet());
System.out.println("After add: "+pets);
pets.addLast(Pets.randomPet());
System.out.println("after addLast: "+pets);
//移除尾部元素
System.out.println("pets.removeLast(): "+pets.removeLast());
}
}
栈通常是指“后进先出的容器”
LinckedList
具有实现栈的全部功能的方法,因此可用LinkedLis
t实现栈
但是如果只需要栈的行为,使用继承LinkedList
的栈就不合适,因为会继承LinkedList
的其他方法
Stack通常有这几类方法
push()
:接受T类型的对象,将其压入栈中
pop()
:移除栈顶元素并返回
peek()
:返回栈顶元素,但部移除
public class TestStack {
public static void main(String[] args) {
Stack
for (String s: "My dog has fleas".split(" ")) {
stringStack.push(s);//入栈
}
System.out.println(stringStack);
while (!stringStack.empty()){//empty()方法判断栈是否为空
System.out.print(stringStack.pop()+"\t");//出栈
}
}
}
练习:将字母压入栈“+”压入,“-” 取出打印
"+U+n+c---+e+r+t---+a-+i-+n+t+y---+-+r+u--+l+e+s"
public class TestStack01 {
public static void main(String[] args) {
char[] s = "+U+n+c---+e+r+t---+a-+i-+n+t+y---+-+r+u--+l+e+s".toCharArray();
charStack(s);
}
public static Stack<Character> charStack ( char[] s){
Stack<Character> characterStack = new Stack<>();
for (int i = 0; i < s.length; i++) {
System.out.println(characterStack);
if (s[i] == '+') {//当遍历到字符数组为加号时,遍历后面元素,检测到非符号时压入栈中
for (int j = i; j < s.length; j++) {
if (!(s[j] == '+' || s[j] == '-')) {
characterStack.push(s[j]);
break;
}
}
} else if (s[i] == '-') {//检测到'-'弹出元素
characterStack.pop();
}
}
return characterStack;
}
}
Set不能保存相同元素,将多个相同实例添加到Set时,就会阻止这种重复现象
Set具有与Collection完全一样的接口,Set实际上就是Collection只是行为不同
public class TestSet {
public static void main(String[] args) {
Random random = new Random(47);
Set<Integer> set = new HashSet<>();
for (int i = 0; i < 10000; i++) {
set.add(random.nextInt(30));
}
System.out.println(set);//HashSet输出无序
}
}
public class TestTreeSet {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<>();
Random rand = new Random(47);
for (int i = 0; i < 1000; i++) {
set.add(rand.nextInt(30));
}
System.out.println(set);//TreeSet输出有序
}
}
Set
操作。
public class SetOperations {
public static void main(String[] args) {
HashSet<String> s1 = new HashSet<>();
Collections.addAll(s1,"A B C D E F G H I J K L".split(" "));
s1.add("M");
System.out.println("Set1 contain H "+s1.contains("H"));
System.out.println("Set1 contain N "+s1.contains("N"));
HashSet<String> s2 = new HashSet<>();
Collections.addAll(s2,"H I J K L".split(" "));
System.out.println("set2 in set1 "+s1.containsAll(s2));
s1.remove("H");
System.out.println("Set1: "+s1);
System.out.println("Set2: "+s2);
System.out.println("set2 in set1 "+s1.containsAll(s2));
s1.removeAll(s2);
System.out.println("set2 removed from set1 "+ s1);
}
}
Map不是collection的子接口或者实现类。Map是一个接口。
Map用于保存具有“映射关系”的数据。每个Entry都持有键-值两个对象。其中,Value可能重复,但是Key不允许重复(和Set类似)。
Map可以有多个Value为null,但是只能有一个Key为null。
实现类
和HashSet集合不能保证元素的顺序一样,HashMap也不能保证key-value对的顺序。并且类似于HashSet判断两个key是否相等的标准一样: 两个key通过equals()方法比较返回true、 同时两个key的hashCode值也必须相等
LinkedHashMap也使用双向链表来维护key-value对的次序,该链表负责维护Map的迭代顺序,与key-value对的插入顺序一致(注意和TreeMap对所有的key-value进行排序区分)
Properties对象在处理属性文件时特别方便(windows平台的.ini文件)。Properties类可以把Map对象和属性文件关联,从而把Map对象的key - value对写入到属性文件中,也可把属性文件中的“属性名-属性值”加载进Map对象中。
TreeMap是一个红黑树结构,每个键值对都作为红黑树的一个节点。TreeMap存储键值对时,需要根据key对节点进行排序,TreeMap可以保证所有的key-value对处于有序状态。 同时,TreeMap也有两种排序方式:自然排序、
public class TestMap {
public static void main(String[] args) {
Map<String,Pet> petMap = new HashMap<>();
petMap.put("MyCat",new Pet("Molly"));
petMap.put("MyDog",new Pet("Ginger"));
System.out.println(petMap);
Pet dog = petMap.get("MyDog");
System.out.println(dog);
System.out.println(petMap.containsKey("MyDog"));
System.out.println(petMap.containsValue(dog));
System.out.println(petMap.entrySet());//entrySet() 方法返回映射中包含的映射的 Set 视图
System.out.println(petMap.values() instanceof Collection);// 获取值返回一个Collection
ArrayList<String> arrayList = new ArrayList<>();
System.out.println(Arrays.asList(1,2,3) instanceof List);
}
}
此接口用于模拟“队列”数据结构(FIFO)。新插入的元素放在队尾,队头存放着保存时间最长的元素
Queue接口与Collections接口中的方法是独立的
实现类
PriorityQueue—— 优先队列(类)
其实它并没有按照插入的顺序来存放元素,而是按照队列中某个属性的大小来排列的。故而叫优先队列。
Deque——双端队列(接口)
ArrayDeque
基于数组的双端队列,类似于ArrayList有一个Object[] 数组。
LinkedList
LinkedList实现
public class TestLinkedListQueue {
public static void printQ(Queue q){
while (q.peek()!=null){//peak()方法返回头部元素
System.out.print(q.peek()+"\t");//remove()方法移除并返回头部元素
q.remove();
}
}
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
Random random = new Random();
for (int i = 0; i < 10; i++) {
queue.offer(random.nextInt(i+10)); //offer()方法入队
}
printQ(queue);
System.out.println();
Queue<Character> characters = new LinkedList<>();
for (char c:"FuckYOU!!!!".toCharArray()){
characters.offer(c);
}
printQ(characters);
}
}
PriorityQueue
优先队列会根据元素的优先级对每个插入的元素进行排序,弹出的每个元素为此时优先级最高的元素
优先队列的排序方式为默认排序方式,也可以提供Comparator来修改排序
//优先队列2参数构造器,容量+比较方法
public PriorityQueue(int initialCapacity,
Comparator<? super E> comparator) {
// Note: This restriction of at least one is not actually needed,
// but continues for 1.5 compatibility
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
public class TestPriorityQueue {
public static void main(String[] args) {
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
Random rand = new Random();
for (int i = 0; i < 10; i++) {
priorityQueue.offer(rand.nextInt(i+10));
}
TestLinkedListQueue.printQ(priorityQueue);
List<Integer> integerList = Arrays.asList(99,2,22,100,2,7,33,1276);
PriorityQueue<Integer> priorityQueue1 = new PriorityQueue<>(integerList);
TestLinkedListQueue.printQ(priorityQueue1); priorityQueue1 = new PriorityQueue<>(integerList.size(), Collections.reverseOrder());//自定义优先级
priorityQueue1.addAll(integerList);
TestLinkedListQueue.printQ(priorityQueue1);
String fact = "SB ZHI YUAN ZHE HUO DONG LANG FEI YE DE SHI JIAN";
List<String> strings = Arrays.asList(fact.split(""));
PriorityQueue<String> priorityQueue2 = new PriorityQueue<String>(strings);
int pq2Size = priorityQueue2.size();
TestLinkedListQueue.printQ(priorityQueue2);
System.out.println(pq2Size);
PriorityQueue<String> priorityQueue3 = new PriorityQueue<>(pq2Size,Collections.reverseOrder());
priorityQueue3.addAll(strings);
TestLinkedListQueue.printQ(priorityQueue3);
}
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章