集合 的体系:
------------| Collection 单例集合的根接口
----------------| List 如果是实现了List接口的集合类,具备的特点: 有序,可重复。
-------------------| ArrayList ArrayList 底层是维护了一个Object数组实现的。 特点: 查询速度快,增删慢。
-------------------| LinkedList LinkedList 底层是使用了链表数据结构实现的, 特点: 查询速度慢,增删快。
-------------------| Vector 底层也是维护了一个Object的数组实现的,实现与ArrayList是一样的,但是Vector是线程安全的,操作效率低。
----------------| Set 如果是实现了Set接口的集合类,具备的特点: 无序,不可重复。
List
List接口中特有方法
添加
- add(int index, E element)
- addAll(int index, Collection<? extends E> c)
获取:
- get(int index)
- indexOf(Object o)
- lastIndexOf(Object o)
- subList(int fromIndex, int toIndex)
修改:
- set(int index, E element)
迭代
- listIterator()
List接口中特有的方法具备的特点: 操作的方法都存在索引值,只有List接口下面的集合类才具备索引值,其他接口下面的集合类都没有索引值。
class Person{
private String name;
private String cardId;
public Person() {
}
public Person(String cardId,String name) {
this.name = name;
this.cardId = cardId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
@Override
public String toString() {
return "id:"+this.cardId+",name:"+this.name;
}
@Override
public boolean equals(Object obj) {
Person p = (Person)obj;
return p.cardId == this.cardId;
}
}
public class Test {
public static void main(String[] args) {
Person p1 = new Person("1","张三");
Person p2 = new Person("2","李四");
Person p3 = new Person("3","王二");
Person p4 = new Person("4","麻子");
List<Person> list1= new ArrayList<>();
list1.add(p1);
list1.add(p2);
list1.add(p3);
List<Person> list2= new ArrayList<>();
list2.add(p1);
//list1.addAll(list2);
//indexOf与lastIndexOf 与contains一样在比较时也是调用Object的equals
//System.out.println(list1.indexOf(new Person("1","李四")) );
//System.out.println(list1.lastIndexOf(new Person("1","李四")) );
//System.out.println(list1.subList(0,1));
//list1.set(1,p3);
//System.out.println(list1);
Iterator<Person> iterator = list1.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
ListIterator特有的方法:
添加:
- hasPrevious() 判断是否存在上一个元素。
- hasNext() 判断是否存在下一个元素。
- previous() 当前指针先向上移动一个单位,然后再取出当前指针指向的元素。
- next(); 先取出当前指针指向的元素,然后指针向下移动一个单位。
- add(E e) 把当前有元素插入到当前指针指向的位置上。
- set(E e) 替换迭代器最后一次返回的元素。
迭代器在变量元素的时候要注意事项: 在迭代器迭代元素 的过程中,不允许使用集合对象改变集合中的元素 个数,如果需要添加或者删除只能使用迭代器的方法进行操作,如果使用过了集合对象改变集合中元素个数那么就会出现ConcurrentModificationException异常。
class Person{
private String name;
private String cardId;
public Person() {
}
public Person(String cardId,String name) {
this.name = name;
this.cardId = cardId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
@Override
public String toString() {
return "id:"+this.cardId+",name:"+this.name;
}
@Override
public boolean equals(Object obj) {
Person p = (Person)obj;
return p.cardId == this.cardId;
}
}
public class Test {
public static void main(String[] args) {
Person p1 = new Person("1","张三");
Person p2 = new Person("2","李四");
Person p3 = new Person("3","王二");
Person p4 = new Person("4","麻子");
List<Person> list1= new ArrayList<>();
list1.add(p1);
list1.add(p2);
list1.add(p3);
list1.add(p4);
ListIterator<Person> listIterator = list1.listIterator();
while(listIterator.hasNext()){
listIterator.next();
}
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
}
}
class Person{
private String name;
private String cardId;
public Person() {
}
public Person(String cardId,String name) {
this.name = name;
this.cardId = cardId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
@Override
public String toString() {
return "id:"+this.cardId+",name:"+this.name;
}
@Override
public boolean equals(Object obj) {
Person p = (Person)obj;
return p.cardId == this.cardId;
}
}
public class Test {
public static void main(String[] args) {
Person p1 = new Person("1","张三");
Person p2 = new Person("2","李四");
Person p3 = new Person("3","王二");
Person p4 = new Person("4","麻子");
List<Person> list1= new ArrayList<>();
list1.add(p1);
list1.add(p2);
list1.add(p3);
list1.add(p4);
ListIterator<Person> listIterator = list1.listIterator();
while(listIterator.hasNext()){
//listIterator.add(new Person("p","p先生"));
listIterator.next();
listIterator.set(new Person("p","p先生"));
}
System.out.println(list1);
}
}
add时返回数据
[id:p,name:p先生, id:1,name:张三, id:p,name:p先生, id:2,name:李四, id:p,name:p先生, id:3,name:王二, id:p,name:p先生, id:4,name:麻子]
set时返回数据
[id:p,name:p先生, id:p,name:p先生, id:p,name:p先生, id:p,name:p先生]
使用三种方式遍历集合的元素.
- 第一种: 使用get方法遍历。
- 第二种: 使用迭代器正序遍历。
- 第三种: 使用foreach遍历。
class Person{
private String name;
private String cardId;
public Person() {
}
public Person(String cardId,String name) {
this.name = name;
this.cardId = cardId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
@Override
public String toString() {
return "id:"+this.cardId+",name:"+this.name;
}
@Override
public boolean equals(Object obj) {
Person p = (Person)obj;
return p.cardId == this.cardId;
}
}
public class Test {
public static void main(String[] args) {
Person p1 = new Person("1","张三");
Person p2 = new Person("2","李四");
Person p3 = new Person("3","王二");
Person p4 = new Person("4","麻子");
List<Person> list1= new ArrayList<>();
list1.add(p1);
list1.add(p2);
list1.add(p3);
list1.add(p4);
//方式一:使用get方法遍历
for (int i = 0; i<list1.size();i++){
System.out.println(list1.get(i));
}
System.out.println("====================");
//方式二:使用迭代器正序遍历
ListIterator<Person> listIterator = list1.listIterator();
while(listIterator.hasNext()){
System.out.println(listIterator.next());
}
System.out.println("====================");
//方式三:使用foreach遍历
for (Person p:list1) {
System.out.println(p);
}
}
}
ArrayList
ArrayList 特有的方法
- ensureCapacity(int minCapaci上ty)
- trimToSize()
ensureCapacity(int n)方法可以对ArrayList低层的数组进行扩容,显示的调用这个函数,如果参数大于低层数组长度的1.5倍,那么这个数组的容量就会被扩容到这个参数值,如果参数小于低层数组长度的1.5倍,那么这个容量就会被扩容到低层数组长度的1.5倍。说这么多,总而言之,记住这个函数可以对低层数组扩容就行了,在适当的时机,好好利用这个函数,将会使我们写出来的程序性能得到提升例如如下两段代码
public class Test {
public static void main(String[] args) {
final int N=1000000;
Object obj=new Object();
ArrayList list1=new ArrayList();
long start=System.currentTimeMillis();
for(int i=0;i<N;i++){
list1.add(obj);
}
System.out.println(System.currentTimeMillis()-start);
ArrayList list2=new ArrayList();
long start2=System.currentTimeMillis();
list2.ensureCapacity(N);//显示的对低层数组进行扩容
for(int i=0;i<N;i++){
list2.add(obj);
}
System.out.println(System.currentTimeMillis()-start2);
}
第2段的效率显然要比第一段高很多,原因是因为,第一段如果没有一次性扩到想要的最大容量的话,它就会在添加元素的过程中,一点一点的进行扩容,要知道对数组扩容是要进行数组拷贝的,这就会浪费大量的时间。如果已经预知容器可能会装多少元素,最好显示的调用ensureCapacity这个方法一次性扩容到位。
ArrayList底层是维护了一个Object数组实现 的,使用无参构造函数时,Object数组默认的容量是10,当长度不够时,自动增长0.5倍。
trimToSize方法将底层数组的长度设置为ArrayList实际的容量,动态增长的多余容量被删除了,我们看下到底是怎么回事。
public static void main(String[] args) {
ArrayList al = new ArrayList(10);
for(int i=0;i<10;i++){
al.add(i);
}
al.add(1);
al.trimToSize();
System.out.println(al);
}
一个初始容量为10的ArrayList,al.add(1);之后,不执行trimToSize时发现debug的内容,发现底层数组的长度是15。
执行到trimToSize时发现debug的内容,发现底层数组的长度是11。
也就是说这个方法将elementData的数组设置为ArrayList实际的容量,动态增长的多余容量被删除了。
有小伙伴反应说他debug的时候,并没有看到elementData长度变为15,这里我猜测一下,你用的应该是idea开发工具。这下面我给出一个idea的debug查看方法,也算小科普一下默认情况下Idea对List类型的显示就是这样的,它过于智能了,所以它只把用户关心的东西显示给你看了,让你的焦点放在最重要的数据上。我们只需要做下一面一步操作,就能看到更详细得信息了:
LinkedList
Linkedlist特有的方法:
方法介绍
- addFirst(E e)
- addLast(E e)
- getFirst()
- getLast()
- removeFirst()
- removeLast()
数据结构
- 栈 (1.6) : 主要是用于实现堆栈数据结构的存储方式。
先进后出
push()
pop() - 队列(双端队列1.5) 主要是为了让我们可以使用LinkedList模拟队列数据结构的存储方式。
先进先出
offer()
poll()
返回逆序的迭代器对象
- descendingIterator() 返回逆序的迭代器对象
public class Test {
public static void main(String[] args) {
LinkedList list= new LinkedList();
list.add("张三");
list.add("李四");
list.add("王五");
/*
list.addFirst("狗娃"); //把元素添加到集合的首位置上。
list.addLast("狗剩"); //把元素添加到集合的末尾处。
System.out.println("获取集合中首位置的元素:"+list.getFirst());
System.out.println("获取集合中末尾的元素:"+ list.getLast());
System.out.println("删除集合中的首位置元素并返回:"+ list.removeFirst());
System.out.println("删除集合中的末尾素并返回:"+ list.removeLast());
list.push("狗娃"); //将该元素插入此集合的开头处。
System.out.println("删除集合的首元素:"+list.pop()); // 移除并返回集合中的第一个元素
list.offer("狗剩");
System.out.println("删除集合的首元素: "+list.poll());
System.out.println("集合中的元素:"+ list);
*/
Iterator it = list.descendingIterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
使用LinkedList实现堆栈数据结构的存储方式与队列的数据结构存储方式。
class Team{
private LinkedList list;
public Team() {
this.list = new LinkedList();
}
public int size(){
return list.size();
}
public boolean offer(Object o){
return list.offer(o);
}
public Object poll(){
return list.poll();
}
}
class Stack{
private LinkedList list;
public Stack() {
this.list = new LinkedList();
}
public int size(){
return list.size();
}
public void push(Object o){
list.push(o);
}
public Object pop(){
return list.pop();
}
}
public class Test {
public static void main(String[] args) {
Team list = new Team();
list.offer("张三");
list.offer("李四");
list.offer("王二");
int size = list.size();
for (int i = 0; i<size;i++){
System.out.println(list.poll());
}
}
}
Vector
ArrayLsit与Vector的区别?
相同点: ArrayList与Vector底层都是使用了Object数组实现的。
不同点:
- ArrayList是线程不同步的,操作效率高,Vector是线程同步的,操作效率低。
- ArrayList是JDK1.2出现,Vector是jdk1.0的时候出现的。
public class Demo1 {
public static void main(String[] args) {
Vector v = new Vector();
//添加元素
v.addElement("张三");
v.addElement("李四");
v.addElement("王五");
//迭代该集合
Enumeration e = v.elements(); //获取迭代器
while(e.hasMoreElements()){
System.out.println(e.nextElement());
}
}
}