黑马程序员_day18_集合框架 List 、Set

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

Collection

一、分为两大类

|--List:列表。

  特点:

  1,有序(存储元素的顺序和取出元素的顺序一致)

  2,该集合中的元素都有索引,所以可以通过索引(角标)来访问元素

  3,它可以存储重复元素。 

|--Set:集:

集中的方法和Collection一致,只要重点注意它的子类对象即可。取出元素只能使用迭代器。

 特点:

1,不包含重复元素。(最大的特点)

2,这个集合存入元素的顺序和取出元素的顺序不一定一致。(具体的容器对象数据结构不同,顺序也有不同)

二、List子接口中的特有方法

因为该接口的特点是 对元素有索引标示。

所以它的特有方法应该都是围绕着索引定义的

1,添加:

void add(index,element);在指定位置加入元素

boolean addAll(index,collection);

2,删除:

object remove(index):获取并删除。记住大家,增加或者删除方法的成功都会改变集合的长度。

3,获取:

获取元素:

Object get(index):获取

获取元素索引:

int indexOf(object);

int lastIndexOf(object);

获取子列表:

List subList(fromIndex,toIndex):获取列表中的一部分,包含fromIndex位置,不包含toIndex位置。

4,修改。

object set(index,element):替换指定位置的元素,并返回被替换掉的元素。

我们发现,List接口是可以对元素进行增删改查的操作的。

注意:只有这个集合具备着增删改查。具备的原因:因为有索引。 

有索引才能增删改查。Collection集合都不具备。

三、获取List集合中所有元素的两种方式

public static void getAllElements(List list){

list.add("abc1");

list.add("abc7");

list.add("abc2");

list.add("abc4");

//第一种:迭代器。

Iterator it = list.iterator();

while(it.hasNext()){

System.out.println(it.next());

}

//第二种:遍历。通过索引完成。

for(int x=0; x<list.size(); x++){

System.out.println("get:"+list.get(x));

}

}

四、相当牛的列表迭代器ListIterator

它的出现能解决Collection的通用迭代器所不能解决的问题如下:

ConcurrentModificationException并发修改异常。

当对集合进行迭代时,在迭代的过程,如果用集合对象对元素进行了修改。而迭代器是不知道的,所以在迭代的过程中就会发生不确定性。

为了避免这种情况的发生,在迭代时,不要使用集合对象对迭代中的元素进行操作。

解决这个问题,list接口中提供了一个特有的迭代器。ListIterator 列表迭代器。

它的父接口是Iterator

一看其方法,add remove set next 它就可以实现在迭代过程中进行元素的增删改查的动作。

它还支持逆向遍历。hasNext()改为hasPrevious(),next()改为previous();

while(it.hasPrevious()){

System.out.println("previous:"+it.previous());

注意:这个列表迭代器只能对List集合使用。

五、List的三个小头目:vectorArrayListLinkedList

|--Vector:jdk1.0就存在了。底层是数组结构的。可变长度数组

延长方式:是原数组长度的一倍

原理:一旦原数组长度不够,会创建新数组,将原数组的元素复制到新数组中,并将新元素添加到新数组中。Vector是同步的。

|--ArrayList:底层是数组结构,也是支持长度可变数组的。

延长方式:原数组的一半。

是不同步的。替代了Vector.因为效率高,单线程不必判断锁浪费资源。 查询效率很高(数据空间是连续的,并有角标)。 但是增删的效率很低(增删会改变容器的长度。而且其后的每个元素都要向前或者向后依次移动一位或多位)。

|--LinkedList:底层是链接列表结构,简称链表结构。是不同步的。这个中结构的好处:对元素的增删非常效率很高(可以直接通过改变链表链上的元素中的头指向和尾指向)。 查询的效率很低(要从头到尾顺着路径查)。

枚举:

枚举接口也是用来取出集合中的元素,但是枚举接口只能取出Vector集合中的元素。

枚举最后被迭代器取代。 

Enumeration en = v.elements();

while(en.hasMoreElements()){

System.out.println(en.nextElement());

}

六、LinkedList 链表的特有方法。

头尾操作方法(链表是两头开放的,有头和尾)

addFirst();

addLast();

getFirst():从头部获取元素,但不删除。如果没有元素,会抛出NoSuchElementException

getLast();

removeFirst():从头部获取元素,但删除。如果没有元素,会抛出NoSuchElementException

removeLast();

举例演示:

LinkedList link = new LinkedList();

// 添加元素。

link.addFirst("abc1");

link.addFirst("abc2");

link.addFirst("abc3");

link.addFirst("abc4");

迭代取出

Iterator it = link.iterator();

while(it.hasNext()){

System.out.println(it.next());

}结果为 abc4abc3abc2abc1

getFirst()方法来获取

System.out.println(link.getFirst());

System.out.println(link.getFirst());结果为abc4abc4

removeFirst()方法来获取

System.out.println(link.removeFirst());

System.out.println(link.removeFirst());结果为abc4abc3

while(!link.isEmpty()){

System.out.println(link.removeLast());removeLastaddFirst。或者反过来都可以做到怎么存进去怎么取出来。

}结果为abc1abc2abc3abc4

七、LinkedList模拟堆栈和队列

介绍两种常见的数据结构。

1,队列: 先进先出。FIFO  first in  first out

2,堆栈: 后进先出。LIFO  Last in  first out

xx题:请用LinkedList模拟一个堆栈或者队列数据结构。

首先:自定义一种列队数据结构的容器。用LinkedList来完成。

就将链表封装到该结构中,最为最基础结构存在。 

public class MyQueue {

private LinkedList link = null;

public MyQueue(){

link = new LinkedList();

}

 往队列中添加元素。

public void myAdd(Object obj){

//调用的是LinkedList的方法。

link.addLast(obj);

}

 获取队列中元素的方法。

public Object myGet(){

return link.removeFirst();

}

 队列中是否为空。

public boolean isNull(){

return link.isEmpty();

}

}

然后在主方法里对其进行调用操作

//创建我的队列对象。

MyQueue myq = new MyQueue();

//给队列中添加元素。

myq.myAdd("abc1");

myq.myAdd("abc2");

myq.myAdd("abc3");

myq.myAdd("abc4");

while(!myq.isNull()){

System.out.println(myq.myGet());

}

}

八、ArrayList 的练习

1、定义一个功能,去除ArrayList中的重复元素。

思路:

1,定义一个集合,用于存储唯一性的元素。

2,迭代已有的集合,将每一个迭代到的元素都到新集合中判断是否包含。如果包含就不存储,如果不包含就存储到新集合中。

3,迭代结束,新集合中存储的都是不重复的元素。

代码体现:

ArrayList al = new ArrayList();

al.add("abc1");

al.add("abc2");

al.add("abc1");

al.add("abc2");

al.add("abc1");

System.out.println(al);

al = getSingleElmenetList(al);

System.out.println(al);

}

public static ArrayList getSingleElmenetList(ArrayList al) {

//1,创建一个新集合。

ArrayList temp = new ArrayList();

//2,迭代原集合。 

Iterator it = al.iterator();

while(it.hasNext()){

Object obj = it.next();

if(!temp.contains(obj)){

//contains(obj)内部依赖的是equals方法。

temp.add(obj);

}

}

return temp;

}被操作的对象是字符串,字符串把Object类中的equals()方法给覆盖了,只要字符串内容相同就为true。但是如果是自定义对象的话,就没有对equals方法进行覆盖。又会有何不同呢

//存储自定义对象Person,如果姓名和年龄相同就是同一个对象。

al.add(new Person("lisi1",21));

al.add(new Person("lisi2",22));

al.add(new Person("lisi2",22));

al.add(new Person("lisi3",23));

al.add(new Person("lisi3",23));

注意:ArrayList判断元素是否相同使用的equals方法。

 比如contains中就是依赖于equals方法。

或者remove方法都是依赖于equals方法。

尤其存储自定义对象时,该对象一定要覆盖equals方法,建立根据对象自身特点的判断相同的依据。

Person类中覆盖equals方法

public boolean equals(Object obj){

if(!(obj instanceof Person))

判断传进来的是否是person类或者其子类。

return false;

Person p = (Person)obj;

return this.name.equals(p.name) && this.age == p.age;

}

九、Set集的小弟 HashSet

HashSet:底层数据结构是哈希表,不保证顺序,是不同步的。

哈希表:提供数组的查询效率而出现的。

将要存储的元素先通过哈希算法算出一个哈希值来标识存储的位置,代表着元素。

要找元素时,先将该元素通过哈希算法算出哈希值,在通过哈希值到哈希表中去查找。

特点:

1,不关系元素的顺序。

2,提高了查询效率。

3,不可能出现重复元素,因为哈希值都不同。即使相同(碰撞),会再次判断两个元素的equals,内容是否相同。

如果内容也相同,不存,如果内容不同,存储。

所以哈希表要保证元素的唯一性,必须要依赖于两个方法。

1,hashCode

2,equals

HashSet的练习演示:

Hashset存储时首先先判断传进来的对象通过哈希算法得出的哈希值是否相同,如果相同,再看equals方法返回的是否为true

HashSet hs = new HashSet();

hs.add(new Person("lisi8",28));

hs.add(new Person("lisi2",22));

hs.add(new Person("lisi2",22));

hs.add(new Person("lisi3",23));

hs.add(new Person("lisi3",23));

hs.add(new Person("lisi4",24));

Iterator it = hs.iterator();

while(it.hasNext()){

System.out.println(it.next());

}

}

往哈希表中存储自定义对象。 

往哈希表中的存储的自定义对象,必须覆盖hashCode方法,和equals方法。

我也不知道这个对象到底存储到哪个容器中去,

那就将hashCodeequalstoString全都覆盖。 创建对象自身的判断相同的依据。

覆盖Object类中的hashCode方法。建立Person对象自己特点的哈希值算法。

public int hashCode(){

final int NUMBER = 27;

return name.hashCode() + age*NUMBER;//*27是为了尽量保证哈希值唯一。

}

 覆盖Object类中的equals方法,建立Person对象。

 判断是否相同的依据。 根据Person自身的特点来判断。

public boolean equals(Object obj){

if(!(obj instanceof Person))

return false;

Person p = (Person)obj;

return this.name.equals(p.name) && this.age == p.age;

}

十、Set集的另一个小弟 TreeSet

可以给Set集合中的元素进行指定顺序的排序。

默认情况下,是通过元素的自然顺序排的序。

它保证元素唯一性的依据是看比较方法的返回结果是否是0.0.就视为元素相同。不存。

TreeSet的练习演示:

要想让自定义的Person对象具备比较大小的功能。

就需要对person对象进行功能的扩展。

Person去实现Comparable接口。让Person具备自然顺序。 覆盖compareTo方法。 

TreeSet ts = new TreeSet();

ts.add(new Person("lisi8",24));

ts.add(new Person("lisi1",27));//ClassCastException:传进来自定义类对象,而该类又没有覆盖compareTo方法。 发生该异常

ts.add(new Person("lisi0",27));

ts.add(new Person("lisi2",22));

ts.add(new Person("lisi9",20));

ts.add(new Person("lisi1",26));

Iterator it = ts.iterator();

while(it.hasNext()){

System.out.println(it.next());

}

Person类中实现comparable接口,覆盖compareTo方法:

public int compareTo(Object o) {

进行对象比较的时候,通常,先比较主要条件,如果主要条 件相同,在比较次要条件。

如果想要按照人的年龄排序,如果年龄相同,再比较一次姓名。

麻烦写法。

// Person p = (Person)o;

// if(this.age>p.age)

// return 1;

// if(this.age==p.age)

// return this.name.compareTo(p.name);

// return -1;

//技巧性写法。

Person p = (Person)o;

int temp = this.age - p.age;

return temp==0?this.name.compareTo(p.name):temp;

先年龄后姓名

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值