随着广西威扬java班的开授,我们的课程分享也开始增加了java开发端的内容,如果你觉得有用,喜欢请记得关注,转发喔!
· 正 · 文 · 来 · 啦 ·
Java集合就是一个容器。面向对象语言对事物的体现都是以对象的形式存在,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。如果往集合里存放基本数据类型,在存取过程中会有个自动装箱和拆箱。
因为容器中数据结构不同,容器有很多种。不断地将共性功能向上抽取,形成了集合体系,称之为集合框架。
集合框架的顶层就称之为Collection接口。所有的集合类都位于java.util包下,查阅API可以得到如下体系结构。在使用一个体系时,原则:参阅顶层内容。建立底层对象。
集合和数组的区别:
1:数组是固定长度的;集合可变长度的。
2:数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
3:数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
Collection<E>接口
Collection:单列集合
|--List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引,允许重复元素。
|--Set:无序(存入和取出顺序有可能不一致),不允许重复元素,必须保证元素的唯一性。
java.util.Collection接口中的共性方法有:
1.添加:
boolean add(Object obj):一次添加一个。
boolean addAll(Collection c):将指定容器中的所有元素添加。
2.删除:
void clear():将集合中的元素全删除,清空集合。
boolean remove(Object o):删除集合中指定的对象。注意:删除成功,集合的长度会改变。
boolean removeAll(Collection c):删除部分元素。部分元素和传入Collection一致。
3.取交集:
boolean retainAll(Collection c):对当前集合中保留和指定集合中的相同的元素。
如果两个集合元素相同,返回false;如果retainAll修改了当前集合,返回true。
4.获取长度:
int size():集合中有几个元素。
5.判断:
boolean isEmpty():集合中是否有元素。
boolean contains(Object o):集合中是否包含指定元素。
boolean containsAll(Collection c)集合中是否包含指定的多个元素。
6.将集合转成数组。
toArray()
toArray([])
下面的代码就是演示Collection中的基本功能。
package ustc.maxiaolun.collection.demo;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo {
public static void main(String[] args) {
Collection coll = new ArrayList();
methodDemo(coll);
System.out.println("------------------");
methodAllDemo();
}
/*
* 演示Collection中的基本功能。
*/
public static void methodDemo(Collection coll){
//1.添加元素。
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
//2.删除
coll.remove("abc2");//移除和添加元素 --> 会改变集合的长度 --> 集合里面实际上存的是对象们的引用
//3.清除。
coll.clear();
//4.判断包含。
System.out.println("contains: "+coll.contains("abc1"));//底层实现判断用的是equals()
System.out.println(coll);
}
/*
* 演示带All的方法。
*/
public static void methodAllDemo(){
//1.创建两个容器。
Collection c1 = new ArrayList();
Collection c2 = new ArrayList();
//2.添加元素。
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c1.add("abc4");
c2.add("abc2");
c2.add("abc3");
c2.add("abc5");
//往c1中添加c2。
c1.addAll(c2);
//判断c1中是否包含c2中的所有元素。
boolean b = c1.containsAll(c2);
System.out.println("b = "+b);
//从c1中删除c2。将c1中和c2相同的元素从c1中删除。
c1.removeAll(c2);
//将c1中和c2不同的元素从c1中删除。保留c1中和c2相同的元素。
c1.retainAll(c2);
System.out.println(c1);
}
}
7.取出集合元素。
Iterator iterator():获取集合中元素上迭代功能的迭代器对象。
Iterator<E>接口
java.util.Iterator接口是一个对 collection 进行迭代的迭代器,作用是取出集合中的元素。
Iterator iterator():获取集合中元素上迭代功能的迭代器对象。
迭代:取出元素的一种方式。有没有啊?有!取一个。还有没有啊?有!取一个。还有没有啊?没有。算了。
迭代器:具备着迭代功能的对象。迭代器对象不需要new。直接通过 iterator()方法获取即可。
迭代器是取出Collection集合中元素的公共方法。
每一个集合都有自己的数据结构,都有特定的取出自己内部元素的方式。为了便于操作所有的容器,取出元素,将容器内部的取出方式按照一个统一的规则向外提供,这个规则就是Iterator接口。
也就说,只要通过该接口就可以取出Collection集合中的元素,至于每一个具体的容器依据自己的数据结构,如何实现的具体取出细节,这个不用关心,这样就降低了取出元素和具体集合的耦合性。
Iterator it = coll.iterator();//获取容器中的迭代器对象,至于这个对象是是什么不重要。这对象肯定符合一个规则Iterator接口。
package ustc.maxiaolun.collection.demo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo {
public static void main(String[] args) {
//1.创建集合。
Collection coll = new ArrayList();
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
//方式一:获取该容器的迭代器。
Iterator it = coll.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//方式二:直接for+alt+/,选择第三个。
for (Iterator it = coll.iterator(); it.hasNext();) {
System.out.println(it.next());
}
System.out.println(it.next());//abc1
System.out.println(it.next());//abc2
System.out.println(it.next());//abc3
System.out.println(it.next());//java.util.NoSuchElementException
}
}
为了降低容器的数据结构和取出容器元素的方法之间的耦合性,把访问、取出容器元素的容器的内部类进行共性抽取,即各种容器的相应内部类都实现了Iterator接口,实现了hasNext()、next()、remove()方法。例如如下截取自ArrayList类的iterator()方法的底层实现代码:
public Iterator<E> iterator() {
return new Itr();//取出ArrayList容器中元素的迭代器功能,返回的是一个Itr()迭代器对象,也就是实现Iterator接口的内部类对象。
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {//-->ArrayList容器的内部类,实现了Iterator迭代接口(迭代器),里面有hasNext()、next()、remove()方法。
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
List<E>接口
List本身是Collection接口的子接口,具备了Collection的所有方法。List集合的具体子类:子类之所以区分是因为内部的数据结构(存储数据的方式)不同。
List:有序(元素存入集合顺序和取出一致),元素都有索引,允许重复元素-->自定义元素类型都要复写equals方法。
|--Vector:底层的数据结构是数组。数组是可变长度的。线程同步的。增删和查询都巨慢!
|--ArrayList:底层的也是数组结构,也是长度可变的。线程不同步的,替代了Vector。增删速度不快。查询速度很快。(因为在内存中是连续空间)
|--LinkedList:底层的数据结构是链表,线程不同步的。增删速度很快。查询速度较慢。(因为在内存中需要一个个查询、判断地址来寻找下一元素)
可变长度数组的原理:
不断new新数组并将原数组元素复制到新数组。即当元素超出数组长度,会产生一个新数组,将原数组的数据复制到新数组中,再将新的元素添加到新数组中。
ArrayList:是按照原数组的50%延长。构造一个初始容量为 10 的空列表。
Vector:是按照原数组的100%延长。
首先学习List体系特有的共性方法,查阅方法发现List的特有方法都有索引(角标),这是该集合最大的特点。也就是说,List的特有方法都是围绕索引(角标)定义的。
List集合支持对元素的增、删、改、查。
1.添加(增):
add(index, element):在指定的索引位插入元素。
addAll(index, collection):在指定的索引位插入一堆元素。
2.删除(删):
remove(index):删除指定索引位的元素。返回被删的元素。
3.获取(查):
element get(index):通过索引获取指定元素。
int indexOf(element):获取指定元素第一次出现的索引位,如果该元素不存在返回—1;所以,通过—1,可以判断一个元素是否存在。
int lastIndexOf(element) :反向索引指定元素的位置。
List subList(start,end) :获取子列表。
4.修改(改):
element set(index, newElement):对指定索引位进行元素的修改。
下面的代码演示了List的特有方法:
package ustc.maxiaolun.list.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
List list = new ArrayList();
methodDemo(list);
}
/*
* 演示List特有的方法。
*/
public static void methodDemo(List list){
//1.常规添加元素。
list.add("abc1");
list.add("abc2");
list.add("abc3");
//2.插入元素。
list.add(1,"hehe");
//3.删除。
list.remove(1);
list.remove(1);
//4.获取。
System.out.println(list.get(3));// java.lang.IndexOutOfBoundsException
System.out.println(list.get(1));
System.out.println(list.indexOf("abc3"));
//5.修改。
list.set(1,"keke");
System.out.println(list);
//6.取出集合中所有的元素。
for (Iterator it = list.iterator(); it.hasNext();) {
System.out.println("iterator: "+it.next());
}
//7.List集合特有的取出方式。遍历。
for (int i = 0; i < list.size(); i++) {
System.out.println("get: "+list.get(i));
}
}
}
5.获取所有元素:
ListIterator listIterator():list集合特有的迭代器。
在进行list列表元素迭代的时候,如果想要在迭代过程中,想要对元素进行操作的时候,比如满足条件添加新元素。会发生ConcurrentModificationException并发修改异常。
导致的原因是:集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现异常情况。
如何解决呢?既然是在迭代中对元素进行操作,找迭代器的方法最为合适。可是Iterator中只有hasNext,next,remove方法。通过查阅的它的子接口,ListIterator,发现该列表迭代器接口具备了对元素的增、删、改、查的动作。
ListIterator是List集合特有的迭代器。
ListIterator it = list.listIterator; //取代Iterator it = list.iterator;
package ustc.maxiaolun.list.demo;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ListIteratorDemo {
public static void main(String[] args) {
List list = new ArrayList();
list.add("abc1");
list.add("abc2");
list.add("abc3");
list.add("abc4");
//需求:在遍历的过程中,如果遍历到abc2,添加一个元素haha
for (Iterator it = list.iterator(); it.hasNext();) {
Object obj = it.next();//java.util.ConcurrentModificationException
if(obj.equals("abc2")){
list.add("haha");
}
}
//上述代码出现的问题:
//迭代器it在操作容器元素,迭代过程中使用了集合对象list同时对元素进行操作。
//产生迭代结果的不确定性,引发了并发修改异常。
//解决思想:在迭代过程中,想要执行一些操作,使用迭代器的方法就可以了。
//使用List集合特有的迭代器:ListIterator,通过List集合的方法listIterator()获取该列表迭代器对象。
//ListIterator可以实现在迭代过程中的增删改查,还可以逆向遍历。(底层使用了List集合的角标)
//总结:在迭代过程中想要对列表List元素进行操作的时候,就要使用列表迭代器ListIterator.
for (ListIterator it = list.listIterator(); it.hasNext();) {
Object obj = it.next();
if(obj.equals("abc2")){
it.add("haha");
}
}
System.out.println(list);//[abc1, abc2, haha, abc3, abc4]
}
}
ArrayList<E>类
接下来先讨论List接口的第一个重要子类:java.util.ArrayList<E>类,我这里先抛开泛型不说,本篇后面有专门阐述。但要注意,由于还没有使用泛型,利用Iterator的next()方法取出的元素必须向下转型,才可使用子类特有方法。针对ArrayList类,我们最需要注意的是,ArrayList的contains方法底层使用的equals方法判别的,所以自定义元素类型中必须复写Object的equals方法。
针对这个问题,我们来讲几个小练习。
练习1: 往ArrayList中存储自定义对象。Person(name, age)
思路:
1.描述Person。
2.定义容器对象。
3.将多个Person对象,存储到集合中。
4.取出Person对象。-->注意自定义对象复写toString方法,直接打印p才有意义。
package ustc.maxiaolun.list.test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import ustc.maxiaolun.domian.Person;
public class ArrayListTest {
public static void main(String[] args) {
//1.创建ArrayList集合对象。
List list = new ArrayList();
//2.添加Person类型的对象。
Person p1 = new Person("lisi1", 21);
Person p2 = new Person("lisi2", 22);
list.add(p1);//add(Object obj)
list.add(p2);
list.add(new Person("lisi3", 23));
//3.取出元素。
for (Iterator it = list.iterator(); it.hasNext();) {
//it.next():取出的元素都是Object类型的。需要用到具体对象内容时,需要向下转型。
Person p = (Person)it.next();
System.out.println(p.getName()+":"+p.getAge());//如果不向下转型,Object类对象没有getName、getAge方法。
}
}
}
练习2:定义功能,去除ArrayList集合中的重复元素。
思路:
1.最后唯一性的元素也很多,可以先定义一个容器用于存储这些唯一性的元素。
2.对原有容器进行元素的获取,并到临时容器中去判断是否存在。容器本身就有这功能,判断元素是否存在。
-->contains()底层原理就是使用的equals(),而且这里用的是String类复写的的equals。
3.存在就不存储,不存在就存储。
4.遍历完原容器后,临时容器中存储的就是唯一性的元素。
package ustc.maxiaolun.list.test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class ArrayListTest2 {
public static void main(String[] args) {
/*
* 练习2:定义功能,去除ArrayList集合中的重复元素。
*/
List list = new ArrayList();
list.add("abc1");
list.add("abc4");
list.add("abc2");
list.add("abc1");
list.add("abc4");
list.add("abc4");
list.add("abc2");
list.add("abc1");
list.add("abc4");
list.add("abc2");
System.out.println(list);//[abc1, abc4, abc2, abc1, abc4, abc4, abc2, abc1, abc4, abc2]
singleElement2(list);
System.out.println(list);//[abc1, abc4, abc2]
}
/*
* 取出重复元素方式一。
* 定义功能,取出重复元素。因为List带有角标,比较容易进行for循环。
*/
public static void singleElement(List list){
for (int x = 0; x < list.size()-1; x++){
Object obj = list.get(x);
for(int y = x+1; y < list.size(); y++){
if (obj.equals(list.get(y))){
list.remove(y--);//记住:remove、add等方法,会改变原数组长度!注意角标变化。
}
}
}
}
/*
* 取出重复元素方式二。
* 思路:
* 1.最后唯一性的元素也很多,可以先定义一个容器用于存储这些唯一性的元素。
* 2.对原有容器进行元素的获取,并到临时容器中去判断是否存在。容器本身就有这功能,判断元素是否存在。
* 3.存在就不存储,不存在就存储。
* 4.遍历完原容器后,临时容器中存储的就是唯一性的元素。
*/
public static void singleElement2(List list){
//1.定义一个临时容器
List temp = new ArrayList();
//2.遍历原容器
for (Iterator it = list.iterator(); it.hasNext();) {
Object obj = (Object) it.next();
//3.在临时容器中判断遍历到的元素是否存在
if(!temp.contains(obj))//contains()底层原理就是使用的equals(),而且这里用的是String类复写的equals。
//如果不存在,就存储到临时容器中
temp.add(obj);
}
//将原容器清空
list.clear();
//将临时容器中的元素都存储到原容器中
list.addAll(temp);
}
}
练习3:ArrayList取出重复的自定义元素。
记住:往集合里面存储自定义元素,该元素所属类一定要覆盖equals、toString方法!
package ustc.maxiaolun.domian;
public class Person{
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
/*
* 建立Person类自己的判断对象是否相同的依据,必须要覆盖Object类中的equals方法。
*/
public boolean equals(Object obj) {
//为了提高效率,如果比较的对象是同一个,直接返回true即可。
if(this == obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("类型错误");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age==p.age;
}
/*@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}*/
}
contains()方法底层调用的是容器中元素对象的equals()方法!这里如果Person类自身不定义equals方法,就使用Object的equals方法,比较的就仅仅是地址了。
package ustc.maxiaolun.list.test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import ustc.maxiaolun.domian.Person;
public class ArrayListTest3 {
public static void main(String[] args) {
/*
* 练习3:ArrayList取出重复的自定义元素。
*
* 记住:往集合里面存储自定义元素,该元素所属类一定要覆盖equals、toString方法!
*/
List list = new ArrayList();
Person p = new Person("li",19);
list.add(p);
list.add(p);//存储了一个地址相同的对象。在equals方法中直接先this==obj即可。
list.add(new Person("li",20));
list.add(new Person("li",23));
list.add(new Person("li",26));
list.add(new Person("li",23));
list.add(new Person("li",26));
list.add(new Person("li",20));
System.out.println(list);
singleElement(list);
System.out.println(list);
}
public static void singleElement(List list){
List temp = new ArrayList();
for (Iterator it = list.iterator(); it.hasNext();) {
Object obj = (Object) it.next();
if(!temp.contains(obj))// --> contains()方法底层调用的是容器中元素对象的equals()方法!
//这里如果Person类自身不定义equals方法,就使用Object的equals方法,比较的就仅仅是地址了。
temp.add(obj);
}
list.clear();
list.addAll(temp);
}
}
LinkedList<E>类
java.util.LinkedList<E>类是List接口的链表实现,可以利用LinkedList实现堆栈、队列结构。它的特有方法有如下这些:
addFirst();
addLast();
在jdk1.6以后:
offerFirst();
offerLast();
getFirst():获取链表中的第一个元素。如果链表为空,抛出NoSuchElementException;
getLast();
在jdk1.6以后:
peekFirst();获取链表中的第一个元素。如果链表为空,返回null。
peekLast();
removeFirst():获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,抛出NoSuchElementException
removeLast();
在jdk1.6以后:
pollFirst();获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,返回null。
pollLast();
package ustc.maxiaolun.list.linkedlist;
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
//1.创建一个链表对象。
LinkedList link = new LinkedList();
//演示xxxFirst()、xxxLast()方法。
//2.添加方法。
link.addFirst("abc1");
link.addFirst("abc2");
link.addFirst("abc3");
//3.获取元素。
System.out.println(link.getFirst());//abc3
System.out.println(link.getFirst());//abc3
//4.删除元素。
System.out.println(link.removeFirst());//abc3
System.out.println(link.removeFirst());//abc2
//5.取出link中所有元素。
while(!link.isEmpty())
System.out.println(link.removeLast());//removeFirst()
link.contains("abc3");//false
}
}
练习:请通过LInkedList实现一个堆栈,或者队列数据结构。
下面给大家分享一下广西威扬对于软件测试的进阶课程大纲:
如果需要详细了解试听或培训课程费用可留下 姓名+联系方式(手机号或微信号),我们会在第一时间为您解答服务!
软件测试零基础班
软件测试周末精品班
java开发班
ISTQB考试班
更多资讯尽在官方网站
www.njzhenghou.com