------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
集合
1.java集合体系
--List接口:元素是有序的,且可以存放重复数据,因为该体系有下标,该体系具备修改功能,修改指定位置的元素。
--ArrayList
--LinkedList
--Vector
特有方法:
凡是可以操作下标的方法都是该体系特有的方法:
1.add(index,element);addAll(index,collection)。
2.remove(index)。
3.indexOf(element);get(index);listInterator();subList(from,to)。
4.set(index,element)。
--Set接口:元素是无序的,不可以存放重复数据。
--HashSet
--TreeSet
集合中存放的并不是对象实体,而是存放对象的地址。
集合中有一个可变长度的int[],接收任意类型的对象地址,之所以能接收任意类型,也是因为不管什么类型,地址都是int型。
2.集合的用处
3.集合类与数组
b.集合类长度是可变的,而数组是固定的。
c.数组中存储的数据一次只能是一个类型。
d.集合可以同时存储多个类型的对象。
4.List集合常用方法
add,addAll(注意:此处的addAll将一个集合的内容添加到当前集合中,但是不是挨个添加,而是作为一个对象,整个添加进来,我们无法匹配其中个别内容,只能匹配整个对象)
2.删除
remove,removeAll,clear,retainAll(求交集)
注意:删除时,有两个重载remove(int index),remove(Object obj)如果传入一个int型,那么不管这个int型是否在合理范围内,都会调用remove(int index)方法,因此可能会报下标越界错误
3.转换
toArray
4.获取
iterator,size
iterator返回一个迭代器,而迭代器是一种取出元素的方式
该方法本质:
由于获取集合元素的步骤较多,不是一个方法能够解决的,因此该功能由一个内部类实现,该内部类实现了Iterator接口,复写了next,hasNext,remove方法,通过iterator()方法获取该内部类对象,该获取类操作的都是外部类的私有的数据部分,因此设为内部类最合适
直接方法返回数据:
也是可以的,但是这样会导致该方法除了有获取的功能,还要有判断的等等,破坏了单一性原则,且外界可以通过该方法直接访问数据,并不安全,因此使用内部类来达到获取的功能更合适
5.判断
contains,containsAll,isEmpty,equals
equals是复写的,用于判断两个集合内的内容是否一致,是通过比较来判断的,也就是说如果内容一致,但是顺序不一致一样被视为不相等,如果集合内存放的是对象,那么比较的是对象的地址
常用方法测试:
测试代码:
class ListTest
{
public static void main(String[] args)
{
ArrayList al = new ArrayList();
al.add("helong001");
al.add("helong002");
al.add("helong003");
al.add("helong004");
//增删改查获取
//增加,可以默认或者指定位置的增加一个或多个数据
al.add("helong005");
al.add(3,"helong006");
ArrayList temp=new ArrayList();temp.add("ldy001");temp.add("ldy002");
al.add(4,temp);
sop(al);
//三种获取方式iterator,listIterator,get
for(Iterator it = al.iterator();it.hasNext();)
{
Object obj = it.next();
if(obj.equals("helong005"))
it.remove();
}
sop(al);
/*
1.集合的add是添加到末尾,而列表迭代器的add是添加到当前元素的后面
2.集合的set需要提供改变的元素的位置索引,而列表迭代器不需要,它就是修改当前元素
3.集合的remove需要提供索引或者元素值,而列表迭代器是删除当前元素
4.如果通过add传入了一个Collection子类对象,那么该对象在集合中作为一个元素存在
例如下例子中,我们无法匹配到"ldy001",因为本质上集合中没有这个对象的地址存在,
有的是temp的地址。
*/
//列表迭代器是List体系特有的,类似于一个加强版的迭代器,功能更丰富
//这也是得益于索引的存在
ListIterator lit = al.listIterator();
while(lit.hasNext())
{
Object obj = lit.next();
if(obj.equals("helong002"))
lit.add("helongadd");
else if(obj.equals("helong006"))
lit.set("helongset");
else if(obj.equals("helong003"))
lit.remove();
else if(obj.equals("ldy001"))
lit.set("ldyset");
else if(obj.equals(temp))
lit.set("add另一个集合到该集合中,在该集合中作为一个对象存在");
}
sop(al);
sop("======================");
while(lit.hasPrevious())
{
sop(lit.previous());
}
sop("======================");
for(int i=0;i<al.size();i++)
{
sop(al.get(i));
}
//测试两个删除操作
ArrayList all=new ArrayList();
all.add(123);all.add(123);
//all.remove(123);//jvm调用的是remove(int index)报异常,下标越界
sop(all);
f("adf");
}
private static void f(String str){sop("f(String str)");}
private static void f(Object obj){sop("f(Object obj)");}
private static void sop(Object obj)
{
System.out.println(obj);
}
}
运行图:
6.特有方法:
List集合特有方法listIterator()返回它特有的迭代器ListIterator:
某个线程在 Collection 上进行迭代时,通常不允许另一个线性修改该 Collection,只限迭代,Vector的枚举方法不会报异常,但结果也是不确定的,因此不建议这么用。
在迭代时,不能通过集合中的方法操作集合中的元素,因为此时这些元素正被迭代器操作,如果此时使用集合方法操作元素会发生并发异常。只能使用迭代器的方法,但是迭代器方法有限,如果需要添加,修改等操作,则需要使用其子类接口,也就是ListIterator,该接口拥有增删改查等方法来操作集合中的数据,之所以它能进行增删改查是因为该体系元素都是有下标的
集合方法和列表迭代器方法对比:
1.集合的add是添加到末尾,而列表迭代器的add是添加到当前元素的后面
2.集合的set需要提供改变的元素的位置索引,而列表迭代器不需要,它就是修改当前元素
3.集合的remove需要提供索引或者元素值,而列表迭代器是删除当前元素
4.如果通过add传入了一个Collection子类对象,那么该对象在集合中作为一个元素存在
遍历元素的方法:
1.迭代器:iterator();
2.列表迭代器:listIterator();
3.集合方法:get()
[4.Vector特有:枚举方式:elements()]
5.List集合子类
特点:查询、修改速度快,使用下标访问很方便,但是插入、删除速度很慢。
Vector(已被ArrayList代替):底层是数组数据结构。
功能与ArrayList一模一样,JDK1.0出现的,而集合框架是1.2版本的,且Vector是线程同步的,效率低,因此使ArrayList,不使用Vector,同时Vector是唯一可以使用枚举取出集合中变量的一个集合类,枚举的功能与迭代器相同,但是由于枚举以及其方法名称过长,以被迭代器取代。
ArrayList和Vector特点:
初始都创建长度为10的数组,当所需长度超过10时,ArrayList做法是new一个15长度的数组,将原本的元素copy进去,再添加新的元素,Vector做法也是如此,只是Vector是开辟一个20长度的数组,所以ArrayList既能使长度可变,又比较节约空间,因此选用ArrayList。
LinkedList:底层使用链表结构存储数据。
特点:插入、删除速度快,因为只需修改两个节点,但是查询、修改很慢。
特有方法:
addFirst,addLast,getFitst,getLast(获得元素,但不删除),removeFirst,removeLast(获得元素,并且删除它)。之所以有这些方法,是因为对于链表,取头尾很简单。
注意:由于上述方法在链表为空时使用会报异常NoSuchElementException,因此不推荐使用。
JDK1.6后出现了替代方法:
addFirst,addLast----->offerFirst,offerLast
getFirst,getLast------>peekFirst,peekLast
removeFirst,removeLast------>pollFitst,pollLast
推荐使用新方法,这些方法会链表为空时使用会返回null。
6.综合小练习
三个子类的使用:
package com.helong.collectiondemo;
import java.util.*;
class Person
{
private String name=null;
Person(String name){this.name=name;}
}
class CollectionDemo
{
public static void main(String[] args)
{
ArrayList al1 = new ArrayList();
al1.add("123");
al1.add("何龙");
al1.add(23.23);
al1.add(true);
al1.add(new Person("LDY"));
sop(al1.size());
sop(al1);
//判断
sop("al1是否包含23.23:"+al1.contains(23.23));
ArrayList al2 = new ArrayList();
al2.add(true);
al2.add(23.23);
al2.add("123");
sop("all是否包含23.23,true,字符串123:"+al1.containsAll(al2));
sop("al1字符串是否为空:"+al1.isEmpty());
sop("al1字符串是否与al2相等:"+al1.equals(al2));
ArrayList al3=new ArrayList();
ArrayList al4=new ArrayList();Person p1=new Person("aaa");
al3.add(1);al3.add(2);al3.add(p1);
al4.add(1);al4.add(2);al4.add(p1);
sop("al3字符串是否与al4相等:"+al3.equals(al4));
//删除
al1.remove("123");
sop("al1中删除字符串123:"+al1);
al1.removeAll(al2);
sop("al1中删除al2的部分:"+al1);
al2.add("何龙");
sop("al1:"+al1);
sop("al2:"+al2);
al1.retainAll(al2);
sop("取al1和al2的交集:"+al1);
//迭代器
//迭代器是一个类,也就是说iterator方法返回这个类的对象,而该类是一个内部类,在ArrayList内部实现的,
//实现了Iterator接口,拥有next,hasNext,remove方法,用于处理获取的功能。
sop("使用迭代器取出al2中的数据:");
for(Iterator it = al2.iterator();it.hasNext();)
{
sop(it.next());
}
/*
1.add(index,element);addAll(index,collection);
2.remove(index);
3.indexOf(element);get(index);listInterator();
4.set(index,element);
*/
//List体系特有的方法,由于该体系是有序的,可以重复的,因此
//它的特有方法有一个共同点:参数都有下标值。
al2.add(3,"muhaha");
sop(al2);
al2.remove(1);
sop(al2);
al2.set(0,'b');
sop(al2);
sop(al2.indexOf('b'));
sop(al2.get(3));
for(ListIterator lit = al2.listIterator();lit.hasNext();)
{
sop(lit.next());
}
//List体系特有的迭代器:ListIterator,该迭代器是Iterator的子类接口,
//拥有更丰富的方法,用于对遍历中对元素进行操作。
//对集合进行遍历,如果遇到java3,则添加一个java33,如果遇到java4则将java4改成java44,
Person pp=new Person("helong");
ArrayList al5=new ArrayList();al5.add("java1");al5.add("java2");al5.add("java3");al5.add("java4");al5.add(pp);
sop(al5);
ListIterator lit = al5.listIterator();
for(;lit.hasNext();)
{
Object obj=lit.next();
if(obj.equals("java3"))lit.add("java33");//列表迭代器的add是将元素插入到当前元素的后面
else if(obj.equals("java4"))lit.set("java44");//列表迭代器的set用传入的参数代替当前元素
else if(obj.equals(pp))lit.set("000");//equals比较对象时比较的仍是地址
}
sop(al5);
sop(lit.hasNext());
sop(lit.hasPrevious());
while(lit.hasPrevious())
{
sop(lit.previous());
}
//测试Vector的枚举方式取到元素
//这种取元素的方式是Vector特有的,与迭代器的功能是重复的,由于枚举的名字以及其方法的名字过长,
//已被迭代器取代
Vector v = new Vector();
v.add("123");
v.add("234");
v.add("345");
for(Enumeration e = v.elements();e.hasMoreElements();)
{
sop(e.nextElement());
}
//LinkedList练习
LinkedList ll = new LinkedList();
ll.add("add");
ll.addFirst("addFirst");
ll.offerFirst("offerFirst");
ll.addLast("addLast");
ll.offerLast("offerLast");
sop(ll);
sop(ll.getFirst());
sop(ll.peekFirst());
sop(ll.getLast());
sop(ll.peekLast());
sop(ll.size());
ll.removeFirst();
sop(ll+":长度:"+ll.size());
ll.removeLast();
sop(ll+":长度:"+ll.size());
ll.pollFirst();
sop(ll+":长度:"+ll.size());
ll.pollLast();
sop(ll+":长度:"+ll.size());
//ll.removeLast();
//ll.removeLast();
//ll.removeLast();报异常;NoSuchElementException
ll.pollLast();
ll.pollLast();
ll.pollLast();//不会报错,只是返回null,使用返回值前判断就可以了,因此推荐使用这个方法
}
private static void sop(Object obj)
{
System.out.println(obj);
}
}
运行图:
手写实现存储结构(数组和链表:数组的自动扩充,链表的节点等)
//手写实现存储结构(数组和链表:数组的自动扩充,链表的节点等)
package com.helong.mylist;
//==============================================
//ArrayList
//实现它的容量自动扩充
//增删改查长度
class MyArrayList
{
private Object[] value=null;
private int size=0;
MyArrayList()
{
value=new Object[10];
}
//增加
public boolean add(Object obj)
{
if(size==value.length)
expansion();
value[size++]=obj;
return true;
}
//删除
public boolean remove(int index)
{
if(index<0||index>=size)
return false;
Object[] temp=new Object[size-1];//使用到数组长度的地方要由size来替代,因为size才是真实的元素个数
for(int i=0,j=0;i<size;i++)
{
if(i!=index)
{
temp[j++]=value[i];
}
}
value=temp;
size--;
return true;
}
//内部调用remove(int index)
public boolean remove(Object obj)
{
for(int i=0;i<size;i++)
{
if(value[i].equals(obj))
{
remove(i);
return true;
}
}
return false;
}
//修改
public boolean set(int index,Object obj)
{
if(index<0||index>=size)
return false;
value[index]=obj;
return true;
}
//获取
public Object get(int index)
{
if(index<0||index>=size)
return null;
return value[index];
}
//长度
public int length()
{
return size;
}
//复写toString方法,使得该类被打印时按照自定义方式输出
public String toString()
{
String str="【";
for(int i=0;i<size;i++)
{
if(i!=size-1)
str+=(value[i]+",");
else
str+=value[i];
}
str+="】";
return str;
}
private boolean expansion()
{
Object[] temp=new Object[value.length+5];
temp=value.clone();
//注意:clone只对一维数组起作用,而不能用于二维数组,
//因为java没有二维数组的概念,而只有数组的数组,二维
//数组存储的是几个一维数组的引用,而使用clone也只是
//拷贝了这几个引用,说白了还是原来那几个一维数组对象。
//如果想用于二维数组,那么就遍历其中的一维数组,挨个
//拷贝一维数组到目标二维数组中的一维数组下。
value=temp;
return true;
}
}
//==============================================
//LinkedList
//节点问题
//MyLinkedList内部有一个节点成员
//增删改查长度
class MyLinkedList
{
private MyNode head=null;
private MyNode tail=null;
//增加
public void add(Object obj)
{
if(head==null)
{
head=tail=new MyNode(null,obj);
}
else
{
MyNode temp=new MyNode(null,obj);
tail.setNext(temp);
tail=temp;
}
}
public void addFirst(Object obj)
{
MyNode temp=new MyNode(head,obj);
head=temp;
}
public void addLast(Object obj)
{
add(obj);
}
//删除并返回删除的元素
public Object removeFirst()
{
if(head==null)return null;
Object temp=head.getObj();
head=head.getNext();
return temp;
}
public Object removeLast()
{
if(tail==null)return null;
Object temp=tail.getObj();
MyNode node =head;
while(node.getNext()!=tail)//查询到倒数第二个节点的位置
{
node=node.getNext();
}
tail=node;
tail.setNext(null);//将该节点设为尾节点
return temp;
}
//清空链表
public void clear()
{
while(head!=null)
{
MyNode temp=head;
head=head.getNext();
temp.setNext(null);
}
tail=head;
}
//获取元素但不删除
public Object getFirst()
{
return head==null?null:head.getObj();
}
public Object getLast()
{
return tail==null?null:tail.getObj();
}
//修改元素
public Object setFirst(Object obj)
{
if(head!=null)
head.setObj(obj);
return head==null?null:obj;
}
public Object setLast(Object obj)
{
if(tail!=null)
tail.setObj(obj);
return tail==null?null:obj;
}
//复写了Object的toString方法,按照自定义方式打印输出
public String toString()
{
String str="【";
MyNode temp=head;
while(temp!=null)
{
if(temp!=tail)
str+=(temp.getObj()+",");
else
str+=temp.getObj();
temp=temp.getNext();
}
str+="】";
return str;
}
}
class MyNode
{
private MyNode next=null;
private Object obj=null;
MyNode(MyNode next,Object obj)
{
this.next=next;
this.obj=obj;
}
public Object getObj()
{
return obj;
}
public MyNode getNext()
{
return next;
}
public void setObj(Object obj)
{
this.obj=obj;
}
public void setNext(MyNode next)
{
this.next=next;
}
}
//==============================================
class MyList
{
public static void main(String[] args)
{
//MyArrayList测试
//增加
printLine();
sop("MyArrayList方法测试:");
MyArrayList mal=new MyArrayList();
mal.add(123);
mal.add("234");
mal.add(23.23);
mal.add("345");
sop(mal.length());
sop(mal);
//删除时,如果传入int,那默认是调用remove(int index)而不是remove(Object obj)
mal.remove(23.23);
sop(mal.length());
sop(mal);
mal.remove("345");
sop(mal.length());
sop(mal);
//按照索引位置修改元素
mal.set(0,"修改这里");
sop(mal);
//获取元素
sop("索引为0的元素:"+mal.get(0));
sop("索引为1的元素:"+mal.get(1));
printLine();
//============================================
//MyLinkedList测试
//增加
sop("MyLinkedList方法测试:");
MyLinkedList mll=new MyLinkedList();
mll.add("123");
mll.add(23.45);
mll.add(true);
sop(mll);
mll.addFirst("start");
mll.addLast("end");
sop(mll);
//删除头结点,尾节点
sop("删除元素:"+mll.removeFirst());
sop(mll);
sop("删除元素:"+mll.removeLast());
sop(mll);
//获取元素
sop("头元素:"+mll.getFirst());
sop("尾元素:"+mll.getLast());
//清空链表
sop("清空链表");
mll.clear();
sop(mll);
//当链表为空时,再取其头尾结点,此处定义成不会报异常会返回null
sop("头元素:"+mll.getFirst());
sop("尾元素:"+mll.getLast());
//修改头尾结点值,注意此时链表并无数据,因此返回null
sop("修改后头元素:"+mll.setFirst("head"));
sop("修改后尾元素:"+mll.setLast("tail"));
mll.add("ldy001");mll.add("ldy002");mll.add("ldy003");mll.add("ldy004");mll.add("ldy005");
sop(mll);
sop("修改后头元素:"+mll.setFirst("head"));
sop("修改后尾元素:"+mll.setLast("tail"));
sop(mll);
}
private static void sop(Object obj)
{
System.out.println(obj);
}
private static void printLine()
{
sop("============================================");
}
}
运行图:
使用LinkedList模拟堆栈和队列数据结构
//使用LinkedList模拟堆栈和队列数据结构
//堆栈:特点先进后出
//队列:特点先进先出
package com.helong.mystackqueue;
import java.util.*;
class MyStack
{
LinkedList value=new LinkedList();
public void push(Object obj)
{
value.offerLast(obj);
}
public Object pop()
{
return value.pollLast();
}
public String toString()
{
return value.toString();
}
}
class MyQueue
{
LinkedList value=new LinkedList();
public void push(Object obj)
{
value.offerLast(obj);
}
public Object pop()
{
return value.pollFirst();
}
public String toString()
{
return value.toString();
}
}
class MyStackQueue
{
public static void main(String[] args)
{
sop("======================================");
//模拟堆栈的进栈,出栈
MyStack ms = new MyStack();
ms.push("no.1");
ms.push("no.2");
ms.push("no.3");
sop(ms);
sop("出栈:"+ms.pop());
sop("出栈:"+ms.pop());
sop("出栈:"+ms.pop());
sop(ms);
sop("======================================");
//模拟队列的入队,出队
MyQueue mq = new MyQueue();
mq.push("队列no.1");
mq.push("队列no.2");
mq.push("队列no.3");
sop(mq);
sop("出队:"+mq.pop());
sop("出队:"+mq.pop());
sop("出队:"+mq.pop());
sop(mq);
}
private static void sop(Object obj)
{
System.out.println(obj);
}
}
运行图:
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------