面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象的最常用的一种方式
数组虽然也可以存储对象,但数组的长度是固定的,集合的长度是可变的
数组中可以存储基本数据类型,集合中只能存储对象
集合的特点:
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象
List集合和Set集合
List 集合元素是有序的,可以重复,因为该集合有索引
ArrayList 底层结构是数组结构,特点查询快,增删较慢,线程不同步
LinkedList 底层结构是链表结构,特点 增删快,查询较慢
Vector 底层结构是数组结构,它是线程同步的,被ArrayList替代了
Set集合 元素是无序的,不可以重复
HashSet 底层结构是哈希表
其保证元素唯一性的原理:
在存入时首先是比较各元素的哈希值,若哈希值相同再调用equals方法,在添加元素时,会调用元素的hashCode方法和equals方法
注意:HashSet集合中删除,判断元素是否存在等方法依赖的方法是hashCode和equals方法
元素在HashSet集合中是没有顺序的,或者说是按照其特定的哈希值排序
TreeSet 底层结构是二叉树
TreeSet集合可以对集合中的元素进行排序
TreeSet集合在添加一个对象时,对象必须具备比较性
TreeSet集合保证元素唯一性的原理:在添加时他会调用所添加元素的compareTo方法
通过返回的值对元素进行排序,若返回0,则认为这两个元素是一样的
该集合对元素进行排序的另一种方法是:自定义一个比较器,并将这个比较器作为参数传给该集合的构造函数,实现comparator接口,复写该接口中的compare方法
集合中的较为常用的共性方法:
boolean add(E e)
确保此 collection 包含指定的元素(可选操作)。
boolean addAll(Collection<? extends E> c)
将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。
void clear()
移除此 collection 中的所有元素(可选操作)。
boolean contains(Object o)
如果此 collection 包含指定的元素,则返回 true。
boolean containsAll(Collection<?> c)
如果此 collection 包含指定 collection 中的所有元素,则返回 true。
boolean equals(Object o)
比较此 collection 与指定对象是否相等。
int hashCode()
返回此 collection 的哈希码值。
boolean isEmpty()
如果此 collection 不包含元素,则返回 true。
Iterator<E> iterator()
返回在此 collection 的元素上进行迭代的迭代器。
boolean remove(Object o)
从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
boolean removeAll(Collection<?> c)
移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。
boolean retainAll(Collection<?> c)
仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。
int size()
返回此 collection 中的元素数。
Object[] toArray()
返回包含此 collection 中所有元素的数组。
对于不同的集合它还具有一些自己特定的方法,如List集合可以通过角标对元素进行操作等,对于一些特定的方法,我们可以通过查阅API文档来学习。
迭代器是集合中取出元素的一种非常重要的方法
List集合:取出集合中的元素
import java.util.*;
class ListDemo
{
public static void main(String[] args)
{
ArrayList a = new ArrayList();
a.add("a");
a.add("b");
a.add("c");
a.add("d");
System.out.println(a);
/*
在取出集合中的元素时,在取出的过程中对集合中的元素进行操作
注意:在使用迭代器的方法取出集合中的元素时,
不能使用集合中的方法在取出的过程中对元素进行操作,
否则会发生 ConcurrentModificationException,并发修改异常
list 集合有其特殊的迭代器方法ListIterator,可以在取出的过程中对元素进行操作
因为该集合每个元素有对应的角标
*/
ListIterator li = a.listIterator();
while(li.hasNext())
{
Object obj = li.next();
if (obj.equals("b"))
{
li.set("f");
}
System.out.println(obj);//obj不会随着对元素的不同操作而改变,它在元素改变之前就已经指向了该元素
}
System.out.println(a);
//逆向遍历集合并取出集合中的元素,这是List集合才具备的方法
while (li.hasPrevious())
{
System.out.println(li.previous());
}
}
}
总结:迭代器是取出集合中元素常用的方法,在取出元素的过程中一般不能对元素进行操作,但对于List集合而言,由于其具有角标的特性,所以在元素的取出过程中,它具备一些特定的对元素进行操作的方法。
用LinkedList模拟队列和堆栈数据结构
队列:先进先出
堆栈:先进后出
思路:
自定义一个类(基于LinkedList),对外提供添加和取出的方法
import java.util.*;
class DuiLie
{
private LinkedList link ;//将link定义在成员位置上,这样每个方法就可以使用这个对象
DuiLie()
{
link = new LinkedList();
}
public void Myadd(Object obj)
{
link.addLast(obj);
}
public Object Myget()
{
//因为获取元素后,那个元素就需要清除,所以这里用remove() 而不用get()
return link.removeFirst();
}
public boolean isNull()
{
return link.isEmpty();
}
}
class LinkedListTest
{
public static void main(String[] args)
{
DuiLie d = new DuiLie();
d.Myadd("a");
d.Myadd("b");
d.Myadd("c");
while(!d.isNull())
{
System.out.println(d.Myget());
}
}
}
总结:由于LinkedList集合它具有对第一个元素和最后一个元素进行操作的方法
通过这几个方法我们可以很好的模拟出队列和堆栈数据结构
需求:将自定义的人对象添加到List集合中,并去除相同的元素
规定同姓名和同年龄为相同的人
思路:
1.先描述人
2.定义方法可以获取人的姓名和年龄
3.复写父类的equals方法,自定义比较的方法
4.提供一个去除相同元素的方法,在迭代的过程中将比较每个人,并将相同的对象去掉
5.打印集合中的元素
import java.util.*;
class Person
{
private String name;
private int age ;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
//覆盖父类中的equals方法,让其按照自定义的方法进行比较
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
throw new RuntimeException("类型转换异常");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
class ArrayListTest
{
public static void main(String[] args)
{
ArrayList a = new ArrayList();
a.add(new Person("zhangsan",21));
a.add(new Person("zhangsan",22));
a.add(new Person("zhangsan",22));
a.add(new Person("zhangsan",24));
a.add(new Person("zhangsan",23));
a.add(new Person("zhangsan",23));
a = singleList(a);
Iterator it = a.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();//it.next()返回的是Object,父类Object中没有getName和getAge等方法,所以需要强转
System.out.println(p.getName()+"...."+p.getAge());
}
}
/*
去除集合中重复的元素
思路:
1.定义一个新的集合
2.在用迭代器取出原集合中的对象时,判断新的集合中有没有那个对象,
如果有则不添加,如果没有则添加
3.将这个新的集合返回
*/
public static ArrayList singleList(ArrayList a)
{
ArrayList a1 = new ArrayList();
Iterator it = a.iterator();
while(it.hasNext())
{
Object obj = it.next();
if(!a1.contains(obj))
/*contains底层调用的是equals方法,所以当传入的对象是自定义时,需要自定义一个equals方法,让其按照自定义的方法进行比较
List 集合中的很多方法底层调用的都是equals方法
*/
a1.add(obj);
}
return a1;
}
}
Set集合:
Set集合是无序的且元素不可以重复
需求:往HashSet集合中存入自定义对象,并保证对象的唯一性
HashSet 集合保证元素唯一性的原理
在存入元素时首先是比较各个元素的哈希值,在哈希值相同的情况下再调用equals方法
所以在描述对象时必须覆盖父类的hashCode()和equals();
class Person
{
private String name;
private int age;
Person(String name, int age)
{
this.name = name;
this.age = age;
}
//覆盖父类的hashCode()方法
public int hashCode()
{
System.out.println(this.name+".....hashCode.....");
return name.hashCode()+age*12;
}
//覆盖父类的equals()方法
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
throw new RuntimeException("类型转换异常");
Person p = (Person)obj;
System.out.println(this.name+"..比较.."+p.name);
return this.name.equals(p.name) && this.age == age ;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
TreeSet集合,可以对元素进行排序,首先对象一定要具备可比较性,可以通过实现Comparable接口让类强制具备比较性,如果默认的排序方式不是所想要的,可以自定义一个比较器,并将这个比较器作为参数传给该集合的构造函数
需求:
将传入的人对象按照年龄排序
自定义一个比较器,让人按照姓名排序
import java.util.*;
class TreeSetDemo
{
public static void main(String[] args)
{
//如果通过构造函数传入比较器,会按照比较器进行排序
TreeSet ts = new TreeSet(new MyCom());
ts.add(new Person("a",35));
ts.add(new Person("d",18));
ts.add(new Person("a",22));
ts.add(new Person("bb",24));
Iterator it = ts.iterator();
while (it.hasNext())
{
Person p = (Person)it.next();
System.out.println(p.getName()+"...."+p.getAge());
}
}
}
class Person implements Comparable
{
private String name ;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
//实现Comparable接口,复写父类的compareTo方法,使其按照自定义的方法排序
public int compareTo(Object obj)
{
if (!(obj instanceof Person))
throw new RuntimeException("不是人对象");
Person p = (Person)obj;
System.out.println(this.name+".....compareTo......."+p.name);
//基本数据类型不能调用compareTo方法,所以要将其包装成对象
int num = new Integer(this.age).compareTo(new Integer(p.age));
if (num==0)
return this.name.compareTo(p.name);
return num;
}
//有可能用到的是hashSet集合,所以要覆盖父类的hashCode()方法
public int hashCode()
{
return this.name.hashCode()+age*12;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
throw new RuntimeException("不是人对象");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age==p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
//自定义一个比较器,实现Comparator接口并覆盖其compare方法,可以自定义一个排序方式
class MyCom implements Comparator
{
public int compare(Object o1,Object o2)
{
Person p1 = (Person)o1;
Person p2 = (Person)o2;
//先比较姓名,在姓名相同的情况下在比较年龄
int num = p1.getName().compareTo(p2.getName());
if(num==0)
return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));
return num;
}
}
总结:当对象有序并且可以重复我们可以将对象存入到List集合中
当对象无序并且不可以重复是我们可以将对象存入到Set集合中,
在选择Set集合时,如果需要对其进行排序,我们可以将其存入到TreeSet集合中