点击打开链点击打开链接 点击打开链接 android培训、<a">点击打开链接 点击打开链接 java培训、期待与您交流!">点击打开链接 点击打开链接
集合类
集合类是存储对象最常用的的一种方式
为什么出现集合类?
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的的一种方式。
数组和集合类同是容器,有何不同?
l 数组虽然也可以存储对象,但长度是固定的,集合长度是可变的
l 数组中可以存储基本数据类型,集合只能存储对象。
集合类的特点:
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
Collection接口:容器,每一个容器对数据的存储方式都有不同,这个存储方式称之为:数据结构。
collection方法:
1.存储
boolean add(E e):参数类型是Object,以便于接受任意类型的对象。
boolean addAll(Collection c):添加容器里所有元素
2.删除
void clear():删除所有元素
boolean remove(Object o):移除单个元素
boolean removeAll(Collection c):移除集合中包含c集合中的所有元素
3.判断
boolean contains(Object o):集合是否存在某个对象
boolean containsAll(Collection c):集合是否包含c集合中的所有元素。
boolean isEmpty():是否包含元素
boolean equals(Object o):返回此Collection与指定对象是否相等。
4.获取
int hashCode():获取集合的哈希码值
int size():元素数,长度
Iterator iterator():返回此collection的元素上进行迭代的迭代器。集合取出元素的方法
boolean retainAll(Collection c):取交集。
Objcet[] toArray():返回包含所有元素的数组
例:
import java.util.*;
class Test15
{
public static void main(String[] args)
{
//创建一个ArrayList集合对象al
ArrayList al=new ArrayList();
//添加元素
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
//创建另一个arrayList集合对象a.
ArrayList a=new ArrayList();
//添加元素
a.add("java01");
a.add("java02");
a.add("java06");
a.add("java07");
sop("原"+al);
al.addAll(a); //把a集合中的元素都添加到al集合中去
sop("添加a"+al);
al.remove("java01"); //删除java01这个元素,al中有2个java01元素,运行结果发现,只删除了第一个。
sop("删除java01"+al);
al.removeAll(a); //删除a集合中包含的所有元素,运行后会发现前面的java02也被删除了
sop("删除a集合里包含的元素"+al);
al.clear(); //清除集合中所有元素,此时集合为空
sop("清除元素"+al);
al.addAll(a); //添加a中所有元素
sop(al.contains("java01")); //判断al集合是否包含java01这个元素
sop(al.containsAll(a)); //判断al集合是否包含a集合中的所有元素
sop(al.isEmpty()); //判断集合是否为空
al.add("java04");
sop(al.equals(a)); //判断两集合是否相等
sop("size"+al.size());
al.add("java03");
sop("交集"+al.retainAll(a)); //取两集合的交集
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
运行结果:
集合中存储的都是对象的引用。
Iterator接口:
方法: E next():返回迭代器的下一个元素
boololean hasNext(): 如果仍有元素可以迭代,返回true。
void remove():将对象引用从集合中删除
Collection:常见子接口
List特点:元素是有序的,元素可以重复,因为该集合体系有索引
Set特点:元素是无序的,元素不可以重复。
List特有方法:凡是可以操作角标的方法都是该体系的特有方法
增
void add(index,element)
boolean addAll(index,Collection)
删
E remove(index)
改
E set(index,element)
查
E get(index)
int indexOf(object)
List subList(int fromIndex,int toIndex)
ListIterator listIterator()
ListIterator:列表迭代器,List集合特有的迭代器
在迭代时。不可以通过集合对象的方法操作集合中的元素,因为会发生concurrentModificationException异常。
所以,在迭代时只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断、取出、删除的操作。
如果想要其他的操作如添加、修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取。
ListIterator的操作方法:
void add(E e):将指定元素插入列表
void remove():从列表中移除由next或previous返回的最后一个元素
void set(E e):用指定元素替换由next或previous返回的最后一个元素
boolean hasNext():以正向遍历列表时,如果列表迭代器还有元素,则返回true
boolean hasPrevious():如果逆向遍历列表,列表迭代器有多个元素,则返回true。
E next():返回列表中的下一个元素
E previous():返回列表的前一个元素
int nextIndex():返回对next的后续调用所返回元素的索引。
int previousIndex():返回对previous的后续调用所返回元素的索引。
List三个子类的异同:
ArrayList:底层的数据结构使用的是数组结构,特点:查询速度快,但是增删稍慢,线程不同步
LinkList:底层的数据结构是链表结构,特点:增删速度快,但是查询稍慢。
Vector:底层的数据结构是数组数据结构,线程同步。被ArrayList替代了。
Vector特点
Enumeration elements():枚举
hasMoreElements()
nextElements()
Linkedlist:特有方法
JDK1.5版本特性:删除、添加如果没有找到,则抛出异常。
Void addFirst(E e):将元素添加到列表的开头
Void addLast(E e):将元素添加到列表的结尾
E getFirst():获取列表的第一个元素
E getLast():获取列表的最后一个元素
E removeFirst():移除并返回此列表的第一个元素
E removeLast(): 移除并返回此列表的最后一个元素
E poll()::移除并获取此列表第一个元素。
E peek():获取但并不移除此列表的头
JDK 1.6版本新特性
E pollFirst():获取并移除此列表第一个元素,如果集合没有,则返回null.
E pollLast():获取并移除此列表第一个元素,如果集合没有,则返回null.
Boolean offerFirst(E e):在此列表的开头插入指定元素
Boolean offerLast(E e):在此列表的结尾插入指定元素
peekFirst():获取但不移除此列表的第一个元素,如果此列表为空,则返回null。
peekLast():获取但不移除此列表的最后个元素,如果此列表为空,则返回null。
/*请模仿堆栈:先进后出和队列:先进先出的模式为LinkedList存取数据
*/
import java.util.*;
class Test16 //堆栈练习题
{
public static void main(String[] args)
{
DuiZhan d=new DuiZhan();
d.myAdd("java01");
d.myAdd("java02");
d.myAdd("java03");
d.myAdd("java04");
while(!d.isNull())
{
sop(d.myGet());
}
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
//队列:先进先出,用addLast每次都把数据往结尾处存,用removeFirst从前头取,
//取一个删除一个,这样就能保证元素先进先出,还能用isEmpty判断一下元素是否取完。
class Duilie
{
private LinkedList link;
Duilie()
{
link=new LinkedList();
}
//存入数据的方法
public void myAdd(Object obj)
{
link.addLast(obj);
}
//取出数据的方法
public Object myGet()
{
return link.removeFirst();
}
//判断数据是否取完的方法
public boolean isNull()
{
return link.isEmpty();
}
}
//堆栈:先进后出,用addLast把数据每次都往结尾处存,用removeLast从最后头取,
//这样先取出的就是后存进去的数据。
class DuiZhan
{
private LinkedList link;
DuiZhan()
{
link=new LinkedList();
}
public void myAdd(Object obj)
{
link.addLast(obj);
}
public Object myGet()
{
return link.removeLast();
}
public boolean isNull()
{
return link.isEmpty();
}
}
<pre class="java" name="code">//做一个去除ArrayList里面重复元素的函数
import java.util.*;
class Test17
{
public static void main(String[] args)
{
ArrayList al=new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java01");
System.out.println(myRemove(al));
}
//去除ArrayList重复元素的函数myRemove,传入一个ArrayList集合,返回一个ArrayList集合。
public static ArrayList myRemove(ArrayList al)
{
//建立一个新的ArrayList集合
ArrayList newal=new ArrayList();
Iterator it=al.iterator();
//遍历传入al集合的所有元素
for(Object obj;it.hasNext();)
{
obj=it.next();
//判断如果新集合里面没有包含旧集合里面的元素,才把元素存入新集合
if(!newal.contains(obj)) //利用contains()判断
newal.add(obj);
}
return newal;
}
}
对与以上例子,如果ArrayList里面存储的不是字符串,而是自定义Person类,这时判断两个Person对象是否一样,比较的是地址值,如果我们需要将两个名字、年龄一样的Person对象看做同一个Person,我们就需要复写equals方法,示例如下:
import java.util.*;
class Test18 //ArrayList练习2
{
public static void main(String[] args)
{
ArrayList al=new ArrayList();
al.add(new Person("张三",12));
al.add(new Person("李四",15));
al.add(new Person("王五",17));
al.add(new Person("张三",12));
//调用去重函数
al=QC(al);
//利用迭代器将去除重复元素以后的集合元素打印出来
Iterator it =al.iterator();
for(Person p;it.hasNext();)
{
p=(Person)it.next();
System.out.println(p.getName()+"....."+p.getAge());
}
}
//这是一个去除ArrayList里面重复元素的函数
public static ArrayList QC(ArrayList al)
{
ArrayList newal=new ArrayList();
Iterator it=al.iterator();
for(Object obj;it.hasNext();)
{
obj=it.next();
if(!newal.contains(obj))
newal.add(obj);
}
return newal;
}
}
//建立person类
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))
return false;
Person p=(Person)obj;
//当姓名和年龄都一样就返回true,否则返回false
return name.equals(p.name) && age==p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
注意:
l 在迭代时循环中next调用一次,hasNext就要判断一次。
l List集合判断元素是否相同,调用的是equals
Set:是无序的(存入和取出的顺序不一定一致),元素不可以一致
Set集合的功能和Collection是一致的。
常见子类:HashSet:底层数据结构是哈希表,线程是非同步的
TreeSet:可以对Set集合中的元素进行排序。底层数据结构:二叉树。保证元素唯一性的依据:compareTo方法return 0;
hashSet是如何保证元素唯一性的呢?
是通过元素的两个方法HashCode和equals来完成
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的HashCode值不同,不会调用equals。
注意:对于判断元素是否存在及删除等操作,依赖的方法是元素的HashCode和equals方法。
排序时,当主体条件相同,一定要判断次要条件。
TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现comparable接口,覆盖compareTo方法。这种方式也称为元素的自然排序或者叫默认排序。
TreeSet排序的第二种排序方式:当元素自身不具备比较性或者具备的比较性不是需要的,这时就需要让集合自身具备比较性。在集合初始化时就有了比较方式。定义比较器,将比较器最为参数传递给TreeSet集合的构造函数。
当两种排序都存在时,以比较器为主。
比较器:定义一个类,实现Comparator接口,覆盖compare覆盖。
import java.util.*;
class Test19
{
public static void main(String[] args)
{
TreeSet ts=new TreeSet(new myComparator());
ts.add("lisi01");
ts.add("aisi00001");
ts.add("cisi01");
ts.add("misi01");
Iterator it=ts.iterator();
for(Object obj;it.hasNext();)
{
System.out.println(it.next());
}
}
}
//自定义的比较器,①继承Comparator接口
class myComparator implements Comparator
{
//②复写里面的compare方法
public int compare(Object o1,Object o2)
{
//这个类是用来比较字符串长短的,所以先要判断传入参数是否为字符串
if(!(o1 instanceof String)|| !(o2 instanceof String))
throw new RuntimeException();
//进行强制转换
String s1=(String)o1;
String s2=(String)o2;
// 当两字符串长度一样时,比较字母自然顺序
if(s1.length()==s2.length())
return s1.compareTo(s2);
//否则比较两字符串的长度
return new Integer(s1.length()).compareTo(new Integer(s2.length()));
}
}
泛型:JDK1.5版本以后出现的新特性,用于解决安全问题,是一个类型安全机制。
好处:1.将运行期间出现问题转移到编译时期,方便程序员解决问题。
2.避免了强制转换麻烦。
泛型格式:通过<>来定义要操作的应用数据类型。
例:ArrayList<String> al=new ArrayList<String>;
什么时候使用?
通常在集合框架中很常见,只要见到<>就要定义泛型。
当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。
泛型类
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展,现在用泛型来完成扩展。
class Demo<T>
{
Public void show<T t>
{
}
}
泛型类定义的泛型在整个类中有效,如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有的操作类型就已经固定了。
为了让不同的方法可以操作不同的类型,而且类型还不确定,那么就可以将类型定义在方法上。
Public <Q> void print(Q q)
{}
特殊之处:静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以定义在方法上。
泛型定义在接口上
import java.util.*;
class Test20 //泛型定义在接口上的两种方法
{
public static void main(String[] args)
{
InterImpl i=new InterImpl();
i.show("hello java!");
InterImple<Integer> in=new InterImple<Integer>();
in.show(2);
}
}
interface Inter<T>
{
void show(T t);
}
class InterImpl implements Inter<String> //第一种,子类时确定好类型
{
public void show(String str)
{
System.out.println(str);
}
}
class InterImple<T> implements Inter<T> //第二种 子类时不确定类型,调用再确认
{
public void show(T t)
{
System.out.println(t);
}
}
泛型的高级应用
泛型限定:如ArrayList<? Extends Person> ?是不明确类型,是一个占位符,也可以叫通配符
? extends E:可以接收E类型或者E类型的子型。上限
? super E:可以接收E类型或者E类型的父型。下限。
Map集合
特点:该集合存储键值对,一对一对往里存,而且要保证键的唯一性。
重要方法:
1.增加
V put(K key,V value):如果出现添加相同的键,那么添加的值会覆盖原有的键对应值,并返回原有键对应的值。如果没有相同的键,返回null.
void putAll(Map<? extends K,? extends V> m):
2.删除
void clear():移除所有映射关系
V remove(Object key):移除会返回键对应的值。没有回返回null
3.判断
boolean containsKey(Object K):是否包含某个键
boolean containsValue(Object v):是否包含某个值
boolean isEmpty():是否包含键值对
4.获取
V get(object key):没有回返回null。可以通过get方法的返回值来判断一个键是否存在
int size():返回键值映射关系数
Collection<V> values():获取map集合中所有的值.
Set<Map.Entry<K,V>> entrySet():返回映射关系的Set视图
Set<k> KeySet():返回此映射中的包含的所有键存入到set集合,因为set具备迭代器。所以可以根据跌倒取出所有的键,再根据get方法,获取每一个键对应的值。
Map的子类
--HashTable:底层是哈希表数据结构,不可以存入null键null值,该集合是线程同步的。
--HashMap:底层是哈希表数据结构,允许使用null键null值,该集合是不同步的。
--TreeMap:底层是二叉树数据结构的,线程不同步,可以用于给map集合中的键进行排序。
Map的两种取出方式
1.KeySet:
Set<String> keySet=map.keySet();
Iterator<String> it=keySet.iterator();
while(it.hasNext())
{
String key=it.next();
String name=map.get(key);
}
Map的取出原理:将Map集合转成Set集合,再通过迭代器取出
2.entrySet():将map集合的映射关系存入到set集合中,而这个关系的数据类型是Map.Entry。
Set<Map.Entry<String,String>> entrySet=map.entrySet();
Iterator<map.Entry<String,String>> it=entrySet.iterator();
While(it.hasNext())
{
Map.Entry<String,String> me=it.next();
String key=me.getKey();
String value=me.getvalue();
}
map.Entry 其实Entry也是一个接口,他是Map接口中的一个内部接口。
Map拓展练习
import java.util.*;
class Test24 //map扩展练习
{
public static void main(String[] args)
{
HashMap<String,List<Student>> yz=new HashMap<String,List<Student>>();
List<Student> ptb=new ArrayList<Student>();
List<Student> jyb=new ArrayList<Student>();
yz.put("普通班",ptb);
yz.put("精英班",jyb);
ptb.add(new Student("zhangsan",15));
ptb.add(new Student("lisi",17));
jyb.add(new Student("wangwu",16));
jyb.add(new Student("zhaoliu",14));
Iterator<String> it=yz.keySet().iterator();
for(String str;it.hasNext();)
{
str=it.next();
System.out.println(str);
getInfo(yz.get(str));
}
}
public static void getInfo(List<Student> b)
{
Iterator<Student> it=b.iterator();
for(Student stu;it.hasNext();)
{
stu=it.next();
System.out.println(stu);
}
}
}
集合工具类:Collections与Arrays
Collections:对集合进行操作的工具类
重要方法:
①排序
static <T extends Comparable<? Super T>> void / sort(List<T> list):根据元素的自然顺序升序排列
Static <T> void / sort(List<T> list,Comparator<? super T> c):根据比较器产生的顺序对指定列表进行排列
②返回最值
static <T extends Object & Comaparable<? super T> > T /max(Collection<? Extends T> coll):根据元素的自然顺序返回给定collection的最大值
static <T> T / max(Collection<? extends T> coll,Comparator<? super T> comp):根据指定比较器产生的顺序,返回给定collection的最大元素。
static <T extends Object & Comaparable<? super T> > T /min(Collection<? Extends T> coll):根据元素的自然顺序返回给定collection的最小值
static <T> T / min(Collection<? extends T> coll,Comparator<? super T> comp):根据指定比较器产生的顺序,返回给定collection的最小值。
③根据二分法查找:
static <T> int /binarySearch(List<? extends Comparable<? super T>> list,T key):根据二分法查找元素,如果搜索键包含在指定列表中,则返回搜索键的索引,否则返回(-插入点-1)
Static <T> int / binarySearch(List<? extends T>list,T key,Comparator<? super T> c):根据二分法查找元素
④替换
static <T> void /fill(List<? super T> list,T obj):将集合中所有元素替换成指定元素
Static <T> boolean / replaceAll(List<T> list,T oldVal ,T newVal):使用另一个值替换列表中所有指定值。
⑤反转
static void / reverse(List<?> list):反转指定列表中所有元素的顺序。
static <T> Comparator<T> / reverseOrder():返回一个比较器,它强行逆转实现了Comparable接口的对象collection的自然顺序
static <T> Comparator<T> / reverseOrder(comparator<T> cmp):返回一个比较器,它强行逆转了指定比较器的顺序。
⑥得到同步的列表或映射
Static <T> List<T> /synchronizedList(List<T> list):返回列表支持的同步列表
Static <T> Set<T> /synchronizedSet(Set<T> s):返回指定Set支持的同步Set
Static <K,V> Map<K,V> /synchronizedMap<Map<K,V> m>:返回指定映射支持的同步映射
⑦其余方法
Static void / swap(List<?> list,int i,int j):在指定列表的指定位置处交换元素
Static void / shuffle(List<?> list):使用默认随机源对指定列表进行置换
练习:将List集合中的部分元素替换成指定元素。CollectionsDemo
import static java.util.Collections.*; //静态导入
import java.util.*;
class CollectionsDemo
{
public static void main(String[] args)
{
List<String> list=new ArrayList<String>();
list.add("java01");
list.add("java02");
list.add("java03");
list.add("java04");
System.out.println(list);
myFill(list,"java",1,3);
System.out.println(list);
}
//将集合中的指定部分(包含头不包含尾)元素替换成指定元素
public static <T> List<T> myFill(List<T> list,T t,int start,int end)
{
for(int i=start;i<end;i++)
{
list.set(i,t);
}
return list;
}
}
Arrays:用于操作数组的工具类,大部分方法已经在学习数组的时候介绍过。
static boolean / deepEquals(Object[] a1,Object[] a2):如果两个指定数组是彼此深层相等的,则返回true。
Static <T> List <T> /asList(T...a):将数组变成List集合。
1.数组变成集合的好处:可以使用集合的思想和方法来操作数组中的元素
2.注意:将数组转成集合,不可以使用集合的增删方法,如果使用增删方法,会发生UnsupportedOperationException.
如果数组中的元素都是对象,那么变成集合时,数组中的元素就会转成集合中的元素。
如果数组中的元素都是基本类型,那么将数组作为集合中的元素存在。
集合变数组:<T> T[] / toArray(T[] a):
1.指定类型数组到底要定义多长?
当指定类型数组长度小于集合的size,那么该方法内部会创建一个新的数组,长度为集合的size。
当指定类型数组长度大于集合的size,那么该方法内部不会创建新数组,而是使用传递进来的数组,所有创建一个刚好等于集合size的数组最优。
2.为什么要将集合变数组?
为了限定对元素的操作。
高级for循环:
格式: for(数据类型 变量名:被遍历的集合或者数组)
{}
高级for循环和迭代器的区别?
高级for循环只能获取集合元素,但是不能对集合进行操作。
迭代器除了遍历外,还可以进行remove集合中元素的动作,如果使用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。
传统for循环和高级for循环的区别?
高级for循环有一个局限性,必须要被遍历的目标,建议在遍历数组时,使用传统for。
JDK1.5版本出现的新特性
Public static void show(int...arr)
{
}
可变参数列表:其实就是数组参数的简写形式,不用每一次都手动建立数组对象,只有将要操作的元素作为参数传递即可,隐式将这些参数封装成了数组。
方法的可变参数使用时注意:可变参数一定要定义在参数列表的最后面。
静态导入:
例:import static java.util.Arrays.*; //导入的是Arrays这个类中的所有静态成员。
当类名重名时,需要指定具体的包名
当方法重名时,指定具备所属的对象或者类
例:import static java.lang.System.*;导入System类中所有的静态成员。
那么我们用输出语句时可以直接用:out.println();