集合
概述:
用于存储对象的可变长度的容器。当对象多了以后,对象也要进行存储,而对象的个数不确定时,无法用数组存储,这时就需要用集合来进行存储。
集合与数组的区别:
数组长度固定,而集合长度是可变的
数组值可以存储对象,还可以存储基本数据类型;而集合只能存储对象
存储数据类型定义数组时就固定了,而集合存储的数据类型不固定
集合的特点:
集合只能存储对象
集合的长度是可变的
集合可以存储不同类型的对象
集合体系:由于容器中的数据结构不同,所以出现了容器的体系,也就是不断向上抽取。
集合中常用类的继承关系
注意:黑粗框中的对象为比较常用的集合对象。
Collection:该接口中定义的除非map集合外其他集合的共性方法
添加 boolean add(obj)
删除 boolean remove(obj)
void clear() 清空
判断
boolean countians(obj)
boolean isEmnty()判断容器中是否有元素,依据的size方法
转换成数组
<T>T[] toArray(T [])
将集合变数组可以限定对集合中的元素进行增删操作,只能进行获取这些元素的操作如果传递的指定的类型的数组的长度大于了集合的size,那么toArray方法,就不会创建新数组,直接使用该数组即可,并将集合中的元素存储到数组中,其他为存储元素的位置默认值null。 所以,在传递指定类型数组时,最好的方式就是指定的长度和size相等的数组。
获取
iterator() 迭代器,利用该方法返回的Iterator 中的方法可通过循环一个一个的进行取出
交集 retainAll(Collection c) al.ratainAll(a2); 在al中保留与a2集合共同的元素
元素个数 int size()
集合变数组 T[] toArray(T[] t)
Iterator 迭代器
所有collection集合共性取出方式
每个容器都有取出功能,这些功能定义都是一样,只不过因为容器的数据机构不同,所以实现的具体方式也不同,从这些定义的声明中进行了抽取,从而出现了Iterator接口,在每一个容器内部对该接口进行了内部类的实现。将取出方式的具体实现方式进行封装,通过iterator方法对外提供能够取出元素的对象
代码示例
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("abc0");
coll.add("abc1");
coll.add("abc2");
//获取迭代器
Iterator it = coll.iterator();
//while循环进行迭代
while(it.hasNext())
{
System.out.println(it.next());
}
注意在使用Iterator迭代器时,不能使用集合方法操作集合,不然会发生并发访问异常,需要对集合进行操作可以使用Iterator的子类LinkIterator
Collection共性方法代码示例
class CollectionDemo
{
public static void main(String[] args) {
Collection coll = new ArrayList();
// show(coll);
Collection c1 = new ArrayList();
Collection c2 = new ArrayList();
show(c1,c2);
}
public static void show(Collection c1,Collection c2){
//给c1添加元素。
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c1.add("abc4");
//给c2添加元素。
c2.add("abc1");
c2.add("abc2");
c2.add("abc3");
c2.add("abc4");
c2.add("abc5");
System.out.println("c1:"+c1);
System.out.println("c2:"+c2);
//演示addAll
// c1.addAll(c2);//将c2中的元素添加到c1中。
//演示removeAll
// boolean b = c1.removeAll(c2);//将两个集合中的相同元素从调用removeAll的集合中删除。
// System.out.println("removeAll:"+b);
//演示containsAll
// boolean b = c1.containsAll(c2);
// System.out.println("containsAll:"+b);
//演示retainAll
boolean b = c1.retainAll(c2);//取交集,保留和指定的集合相同的元素,而删除不同的元素。
//和removeAll功能相反。
System.out.println("retainAll:"+b);
System.out.println("c1:"+c1);
}
public static void show(Collection coll){
//1,添加元素。add.
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
System.out.println(coll);
//2,删除元素。remove
// coll.remove("abc2");//会改变集合的长度
//清空集合.
// coll.clear();
System.out.println(coll.contains("abc3"));
System.out.println(coll);
}
}
List 有序的可重复有序是指在集合中所在的顺序与存入的顺序有关联。
List中特有方法
添加 add(index,obj)
删除 remove(index )
获取 get(index)
索引 indexOf(obj)第一次出现的索引 lastIndexOf(obj)最后一次出现的索引如不包含则两个方法都返回-1
获取子列表subList(start,end)
修改替代 set(index obj)
List集合支持列表迭代器ListIterator
Iterator在迭代时只能进行判断hasNext获取next()和删除remove()操作,
因此出现了具有更多方法的ListIterator子接口在迭代List集合时,还可以对元素进行其他多种操作
代码示例
class ListDemo2
{
public static void main(String[] args)
{
List list = new ArrayList();
//show(list);
list.add("abc1");
list.add("abc2");
list.add("abc3");
System.out.println("list:"+list);
ListIterator it = list.listIterator();//获取列表迭代器对象
//它可以实现在迭代过程中完成对元素的增删改查。
//注意:只有list集合具备该迭代功能.
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("abc2")){
it.set("abc9");
}
}
// System.out.println("hasNext:"+it.hasNext());
// System.out.println("hasPrevious:"+it.hasPrevious());
while(it.hasPrevious()){
System.out.println("previous:"+it.previous());
}
System.out.println("list:"+list);
注意ListIterator迭代器 List集合特有。
ArryList 底层是数组数据结构,jdk1.2出现线程是不同步的,查询速度很快,增删很麻烦。当要使用的List集合需要进行较多的查询而增删较少时建议使用该集合
去除ArrayList中的重复元素代码示例
class ArrayListTest2
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();
ArrayList al = new ArrayList();
al.add("abc1");
al.add("abc2");
al.add("abc2");
al.add("abc1");
al.add("abc");
al.add("abc1");
al.add("abc");
System.out.println(al);
al = getSingleElement(al);
System.out.println(al);
}
}
public static ArrayList getSingleElement(ArrayList al) {
//1,定义一个临时容器。
ArrayList temp = new ArrayList();
//2,迭代al集合。
Iterator it = al.iterator();
while(it.hasNext()){
Object obj = it.next();
//3,判断被迭代到的元素是否在临时容器存在。
if(!temp.contains(obj)){
temp.add(obj);
}
}
return temp;
}
Vector 底层是数组数据结构,jdk1.0出现,线程是同步的,效率低。被ArrayList取代
该集合中有特有的取出方式枚举(Enumeration)因为枚举的功能和Iterator是一致的,并且方法名过长,因此也被Iterator取代
代码示例
class VectorDemo
{
public static void main(String[] args)
{
Vector v = new Vector();
v.addElement("abc1");
v.addElement("abc2");
v.addElement("abc3");
v.addElement("abc4");
Enumeration en = v.elements();
while(en.hasMoreElements()){
System.out.println("nextelment:"+en.nextElement());
}
Iterator it = v.iterator();
while(it.hasNext()){
System.out.println("next:"+it.next());
}
}
}
LinkList 底层是链表数据结构,线程是不同步的,增删速度很快
特有方法
addFirst() jdk1.6 offerFist() 添加至第一个
addLast() jdk1.6 offerLast() 添加至最后一个
getFirst() jdk1.6 peekFist() 获取第一个
getLast() jdk1.6 peekLast() 获取最后一个
removeFirst() jdk1.6 pollFist() 删除第一个
removeLast() jdk1.6 pollLast() 删除最后一个
注意:
对于获取和删除,如果容器中没有元素,则会抛出NoSuchElementExecption
使用1.6出现的新方法时,容器中没有元素,返回null
代码示例
class LinkedListDemo1
{
public static void main(String[] args)
{
LinkedList link = new LinkedList();
link.addFirst("abc1");
link.addFirst("abc2");
link.addFirst("abc3");
link.addFirst("abc4");
// System.out.println(link);
// System.out.println(link.getFirst());//获取第一个但不删除。
// System.out.println(link.removeFirst());//获取元素但是会删除。
// System.out.println(link.removeFirst());
while(!link.isEmpty()){
System.out.println(link.removeLast());
}
System.out.println(link);
// Iterator it = link.iterator();
// while(it.hasNext()){
// System.out.println(it.next());
// }
}
}
利用LinkList模拟堆栈
代码示例
class DuiLie
{
private LinkedList link;
DuiLie
{
link=new LinkedList();
}
public void myAdd(Object obj)
{
Link.addFirst(obj);
}
public Object myGet()
{
Link.removeLast(obj);
}
public boolean isNull()
{
Link.isEmpty;
}
}
class LinkedListDemo2
{
public static void main(String[] args)
{
DuiLie link = new DuiLie ();
link.myAdd("abc1");
link.myAdd ("abc2");
link.myAdd ("abc3");
link.myAdd "abc4");
while(link.isNull)
{
System.out.ptinrln(link.myGet());
}
}
Set 无序不可重复的。该集合中没有特有的方法直接继承与colltection
Hashset 数据类型结构是哈希表,该集合判断两个元素是否重复通过元素的两个方法hashcCode()和equals(),先判断元素的hashCode返回值是否一致,当返回值一致时再去判断equals()方法,当equals判断为true时就会认为这两个元素是同一个元素。
哈希表的原理:
1,对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。
2,哈希值就是这个元素的位置。
3,如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。
4,存储哈希值的结构,我们称为哈希表。
5,既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。
这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。
对于ArrayList集合,判断元素是否存在,或者删元素底层依据都是equals方法。
对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。
注意复写hashCode()方法时,尽量依据元素的判断相同的条件来定义hashCode的返回值。
小练习往hashSet集合中存储Person对象。如果姓名和年龄相同,视为同一个人。视为相同元素。
代码示例
public class Person implements Comparable
{
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public int hashCode() {
System.out.println(this+".......hashCode");
return name.hashCode()+age*27;
}
public boolean equals(Object obj) {
if(this == obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("类型错误");
System.out.println(this+"....equals....."+obj);
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.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;
}
public String toString(){
return name+":"+age;
}
public int compareTo(Object o) {
Person p = (Person)o;
int temp = this.age-p.age;
return temp==0?this.name.compareTo(p.name):temp;
}
}
class HashSetTest
{
public static void main(String[] args)
{
HashSet hs = new HashSet();
/*
HashSet集合数据结构是哈希表,所以存储元素的时候,
使用的元素的hashCode方法来确定位置,如果位置相同,在通过元素的equals来确定是否相同。*/
hs.add(new Person("lisi4",24));
hs.add(new Person("lisi7",27));
hs.add(new Person("lisi1",21));
hs.add(new Person("lisi9",29));
hs.add(new Person("lisi7",27));
Iterator it = hs.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p);
// System.out.println(p.getName()+"...."+p.getAge());
}
}
}
TreeSet 数据类型结构是二叉树,判断元素是否相同通过比较方法返回值,当return 0时,该两个元素相同
特点可以对set集合中的元素进行排序
二叉树排序图解
排序的两种方法
一让元素自身具备比较性
也就是让元素自身实现Comparable接口覆盖compareTo方法
这种排序方式也称为元素的自然排序,也可称为默认排序
代码示例-person类代码同上
public class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
//以Person对象年龄进行从小到大的排序。
ts.add(new Person("zhangsan",28));
ts.add(new Person("lisi",21));
ts.add(new Person("zhouqi",29));
ts.add(new Person("zhaoliu",25));
ts.add(new Person("wangu",24));
Iterator it = ts.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
二让容器具备比较性,需要自定义一个比较器,将比较器作为参数传递给TreeSet集和的构造函数
需求当元素自身不具备比较性,或者元素本身具备的比较性不是所需要的时
那么这时就只能让容器自身具备
定义一个类实现Comparator接口,覆盖compare方法
代码示例
class ComparatorByName implements Comparator
{
public int compare(Object o1, Object o2)
{
Person p1 = (Person)o1;
Person p2 = (Person)o2;
int temp = p1.getName().compareTo(p2.getName());
return temp==0?p1.getAge()-p2.getAge(): temp;
}
}
public class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new ComparatorByName());
//以Person对象年龄进行从小到大的排序。
ts.add(new Person("zhangsan",28));
ts.add(new Person("lisi",21));
ts.add(new Person("zhouqi",29));
ts.add(new Person("zhaoliu",25));
ts.add(new Person("wangu",24));
Iterator it = ts.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
注意
当两种比较方式同时存在时以容器自身比较方法为主,也就是以比较器中的方法为主。
在定义两种比较方法时,都应明确比较的主要条件相等时,需要判断次要条件
技巧
如何判断容器的数据结构,通过其名称前缀即可
ArrayList
LinkdeList
HashSet
TreeSet
HashMap
TreeMap
看到array 就要想到角标
看到 link 就要想到first 和last
看到 hash 就要想到 hashCode 和equals方法
看到 Tree 就要想到 Comparable 和Comparator接口
黑马程序员-java基础之集合List,Set集合
最新推荐文章于 2020-06-03 15:51:10 发布