黑马程序员—java基础之集合
------- android培训、java培训、期待与您交流! ----------
感恩,感恩,感恩!懂得感恩的人,才会是有福报的人!感谢所有发生的一切!
什么是集合:集合是一个容器. 还记得数组也是一个容器,那么他们之间有什么不同呢.
集合与数组比较
数组有什么特点?
1.有顺序
2.定长
3.类型单一
集合特点:
1.有顺序也可以没顺序
2.集合长度可以随着元素的增加而增加
3.集合中可以装入任何Object
Java中的集合类都在java.util包下
Java中的集合元素全是Object类型的。
Collection集合
Collection(特点:有顺序也无顺序,可重复也不可重复)
它是一个接口,下面是它的子接口.
|---List:有顺序的可重复
|----ArrayList
|----LinkedList
|----Vector
|---Set :无顺序不可重复
|-----HashSet
|-----TreeSet
重复的概念是两个元素做equals相等
Collection接口中声明的方法
1.add 向集合中添加元素
声明:public boolean add(Object obj)
作用:向集合添加元素obj
参数:要添加的元素
返回值:代表是否添加成功.
2.clear清空集合中的元素
声明:public void clear();
作用:清空集合中所有元素
3.contains判断集合中是否包含指定元素
声明:public boolean contains(Object obj)
作用:判断集合中是否包含指定元素,如果包含返回true,不包含返回false;
注意:所谓的包含是指obj与集合中的元素做equals返回true.
4.size
声明:public int size();
作用:返回集合中元素的个数
5.isEmpty
声明:public boolean isEmpty();
作用:判断集合中是否包含元素,如果没有任何元素返回true,有元素返回false
6.remove
声明:public boolean remove(Object obj)
作用:删除集合中的指定元素obj,如果删除成功返回true,否则返回false
注意:一次只能删除一个.
Collection中的所有带All方法
1.addAll
声明:public boolena addAll(Collection c);
作用:求两个集合的并集
简单说就是将两个集合中内容合并
2.containsAll
声明:public boolean containsAll(Collection c)
作用:判断集合c是否是集合的子集
3.removeAll
声明:public boolean removeAll(Collection c);
作用:将集合中包含的c集合中的所有元素删除。如果一个都不包含,返回false;
4.retainAll
声明:public boolean retainAll(Collection c);
作用:得到两个集合的交集.
Collection中的迭代器(****)
想要将集合中的所有元素取出来,需要使用迭代器.
声明:public Iterator iterator();
Iterator它是对Collection进行迭代的迭代器(简单说就是用来遍历 Collection集合的)
Iterator接口中的方法
1.hasNext
声明:public boolean hasNext();
作用:判断集合中是否有元素可以进行迭代
2.next
声明:public Object next();
作用:将下一个迭代出来。
3.remove
声明
publicvoid remvoe();
作用: 删除元素
使用迭代器遍历集合元素步骤
1.创建迭代器
Iteratorit=集合对象.iterator();
2.通过迭代器判断是否有元素可以进行迭代
while(it.hasNext()){它返回的是boolean 值
}
3.通过迭代器将元素迭代出来
Objectobj=it.next();
集合中的元素在迭代出来后,都是Obejct
关于迭代器的问题
iterator这个方法是声明在Collection接口中.
Iteratorit=集合对象.iterator();
在迭代的过程中不能对集合中元素进行修改,如果修改产生java.util.ConcurrentModificationException
关于迭代器中的remove方法与Collection中的方法区别
在对集合使用迭代器操作的过程中,不允许使用集合提供的可以修改集合中元素的方法。
例如:将集合中的元素删除,如果想要删除,必须使用迭代器提供的行为.
迭代器的实现伪代码
interfaceIterator{
}
interfaceCollection{
Iteratoriterator();
}
classArrayList implements Collection{
publicIterator iterator(){
returnnew Iter();
}
class Iter implements Iterator{
}
}
classLinkedList implements Collection{
publicIterator iterator(){
returnnew LinkedIter();
}
classLinkedIter implements Iterator
{
}
}
Collection c=new ArrayList();
Iteratorit=c.iterator();
List集合
List集合的特点:有顺序可重复
List是继承自Collection,Collection中的方法在List中都是存在。
List集合是有索引的,我们可以通过索引对其元素进行精确控制.
List集合中的特性方法:
1.add方法
声明:public void add(int index,Object obj);
作用:在指定index索引位置添加元素
2.get方法(***)
声明:public Object get(int index);
作用:根据索引index得到对应位置上的元素
3.remove方法
声明:public Object remove(int index);
作用:将指定index索引位置上的元素删除,返回值就是删除的元素.
4.set方法
声明:public Object set(int index,Object obj)
作用:使用obj将index位置上的元素替换,返回值是被替换的元素.
List集合的遍历方式
1.通用方式 Iterator(适用于所有的Collection集合)
通过从Collection继承的iterator方法
2.使用get(只适用于List集合)
因为List集合是有顺序的,我们可以通过索引对其位置上进行控制
3.使用List集合的特有的迭代器械 ListIterator(只适用于List集合)
ListIterator是继承自Iterator,也就是在Iterator中声明的hasNext,next,remove方法它也有。
但是它还提供了特有的方法
add
set
ListIterator比Iterator功能增强
1.Iterator只能从上到下遍历,而ListIterator可以双向遍历
2.Iterator在迭代过程中不能修改,而ListIterator可以add ,set
ArrayList
它实现了List集合,所以在List集合中的方法它都可以用
我们主要研究,ArrayList的实现方式
ArrayList它的实现是使用可变数组
ArrayList类的特点:
1.它的底层实现是使用数组实现。
2.每一次数组会扩充50%
3.它是线程不安全。在单线程中使用。
//扩充方式伪代码:
classMyList{
privateObject[] obj;
privateint size=0;
publicMyList(){
this(10);
}
publicMyList(int len){
obj=newObject[len];
}
publicvoid add(Object o){
obj[size]=o;
//为了实现可以一直向MyList中不断的添加元素.
change();
size++;
}
privatevoid change(){
Object[]old=obj;
obj=newObject[old.length*3/2]; //在原来数组基础上扩大50%
/*
for(inti=0;i<old.length;i++){
obj[i]=old[i];
}*/
}
publicString toString(){
StringBuilderbuilder=new StringBuilder();
builder.append("[");
for(inti=0;i<size;i++){
builder.append(obj[i]).append(",");
}
builder.deleteCharAt(builder.length()-1);
builder.append("]");
returnbuilder.toString();
}
}
LinkedList
LinkedList的底层实现:双向链表
LinkedList特殊的方法:它可以很方便的操作集合的头尾元素.
它对外提供了 get/remove/add
关于ArrayList与LinkedList集合区别?
ArrayList底层是使用数组实现,在内存中是连续的空间,那么他在做查找时会方法,
但是在做删除/修改时效率比较低.
LinkedList它的底层实现是链表实现,它在做查找时效率比较低。转为每一个元素
头存储的是上一个元素的地址,尾存储的是下一个元素的地址。
但是,它在做删除与修改时效率高。
LinkedList集合的特性方法
1.addFirst/addLast
声明:public void addFirst(Object obj);
作用:将obj元素添加到集合的首位置
声明:public void addLast(Object obj)
作用:将obj元素添加到集合的尾位置
//在jdk1.6后提供两个替代的方法
offerFirst
offerLast
它与我们addFirst与addLast区别在于它有返回值.
2.getFirst/getLast
声明:public Object getFirst();
作用:得到集合中的首元素
声明:public Object getLast();
作用:得到集合的尾元素
在jdk1.6后提供替代方法
peekFirst
peekLast
它们与getFirst/getLast区别,它们在集合为空时,返回的是null,而不会产生异常.
3.removeFirst/removeLast
声明:public Object removeFirst();
作用:删除集合中的首元素,返回的就是删除的这个元素
声明:public Object removeLast()
作用:删除集合中的最后一个元素,返回的是删除的这个元素.
jdk1.6后替换的方法
pollFirst
pollLast
它们区别在于pllFirst/pollLast列表为空时不会产生异常,而是返回null;
注意:对于getFirst/getLastremoveFirst/removeLast时,如果集合为空
会产生异常.
Vector
Vector是早期应用集合时所使用的一个类.
ArrayList是Vector的替代类.
ArrayList是数组实现,它是每次增加50%,线程不安全.
Vector是数组实现 它每次拉回100%,线程安全的。
关于使用Enumeration遍历Vector
//1.得到Enumeration对象
Enumeration enu=v.elements();
//2.判断是否有元素可以进行迭代
while(enu.hasMoreElements()){
//3.得到元素
Object obj=enu.nextElement();
System.out.println(obj);
}
List集合的总结
List有顺序可重复.
|----ArrayList
它的底层实现是使用数组,每次增长50%,在做查询操作时效率高。是线程不安全。
|----LinkedList
它的底层实现是使用链表,它在做修改与删除时效率高。线程不安全。
Linkedlist对于首尾元素操作比较方便.
|----Vector
它的底层实现是数组,每次增长100%,效率低下,线程安全。
对于List集合的遍历方式
1.Iterator
2.get+索引
3.listIterator
Set
Set集合:无顺序不可重复
|----HashSet
它是由hash表支持的。这使用hashCdoe与equals来维护元素的唯一
|----TreeSet
对于Set集合,如果想要遍历出所有元素,只能使用迭代器.
元素不重复,是指元素做equals为true,代表重复.
HashSet怎样保证元素唯一
1.两个元素的hashCode不一样,不会判断equals,直接就能装入.
2.两个元素的hashCode一样,equals为false,能装入
3.两个元素的hashCdoe一样,equals为true,不能装入.
做equals相等的对象的hashCode值应该一样.
我们重写hashCode方法时怎样重写
就是将所有的做equals比较进应用的属性的hashCode值进行相加就可以,
为了减少重复的概率,我们可以定义一个质数,用这个质数与
所有的属性相乘,这样使用的hashCode值重复概率减少.
TreeSet集合的特点:有顺序不可重复
TreeSet集合怎样保证集合中的的元素是有顺序的,怎样保证元素的唯一性
TreeSet集合中的元素必须有自然顺序或给集合指定了比较器。
1.使用自然顺序
就是实现 Comparable接口,重写compareTo方法
怎样排序:根据compareTo方法的返回值是正数还是负数,知道大于还是小于.
怎样唯一:根据compareTo方法的返回值为0,知道重复.
2.使用比较器
就是实现 Comparator接口 重写compare方法。
怎样排序:根据compare方法的返回值是正数还是负数,知道大于还是小于.
怎样唯一:根据compare方法的返回值为0,知道重复.
注意:使用比较器要在创建集合时,就将其做为参数传递给集合。
什么时候使用比较器?
我们在开发中,发现集合中的元素已经存在了自然顺序,但是我们
想要进行排序的条件不是按照元素的自然顺序排序。这时就可以
自己去做比较器。
Set
|----HashSet 底层使用的hash表无顺序不重复,线程不安全的。 这是使用hashCode和equals方法保证元素唯一
|------LinkedHashSet
元素装入顺序与取出顺序一致.线程不安全
|----TreeSet
底层使用二叉树有顺序,不可重复 线程不安全的.TreeSet在使用时效率比较低。
它保证元素唯一有两种方式
1.自然顺序 Comparable----compareTo(Object obj)
2.比较器 Comparator----compare(Object o1,Object o1)
怎样选择List与Set集合
通常使用List,首先ArrayList ,如果是操作头尾元素还有频繁进行删除修改操作这时选择LinkedList
如果要求元素是不重复的。
这时就选择Set ,首先HashSet
如果要求对元素进行排序 TreeSet.
jdk1.5,jdk1.6中TreeSet集合在使用时,如果是装入的第一个元素,
这个时候它不会进行比较。也就是compareTo方法不会被执行.
jdk1.7后集合中元素必须有自然顺序,也就是说当装入元素时,
无论是否是第一个都会执行compareTo方法。
泛型
泛型:其实就是用来限定类型.
泛型的优点:
1.提高了我们程序的使用性.不需要在自己去做强转.
2.将原来在运行阶段处理的问题,放到了编译阶段.
3.提高安全性.
在我们学习过程中,使用泛型最多的就是在集合中。
泛型可以声明在类上,可以声明在方法上,可以声明在接口上。
声明在类上的泛型,在整个类的范围内都可以使用。
声明在方法上的泛型,只能在方法上使用。什么时候在方法上声明泛型?
类上已经声明了泛型,但是在方法上我们不使用类上的泛型,而是自定义的
一个,那么就可以在方法上声明,注意:在方法上声明时,泛型要定义在方法的返回值前面。
通配符: ? 泛型中使用通配符的限定
<?extends E> 它是用来限定是E类型或是E的子类型.
<?super E> 只能是E类型或E的父类型.
1.关于迭代器中使用泛型
集合上定义了泛型,我们在使用迭代器进行迭代操作时,必须给迭代器
也指定泛型,这样,在迭代出来时就不需要进行强制转换。
2.关于泛型的擦除.
泛型只对编译阶段有效,而在运行阶段就失效。
/*
//以下两种操作,不建议使用,什么情况下能使用,就是为了兼容以前定义的集合.
Listlist1=new ArrayList<String>();
list1.add("abc");
list1.add(123);
List<String>list2=new ArrayList();
list2.add("abc");
list2.add(123);
*/
ArrayList<String>list=new ArrayList<>(); //在jdk1.7后可以,简化操作,<>代表<String>
Map集合
Map集合是一种双列集合,它是采用key-value映射方式存储的。
它的key值不能重复。
Map接口下提供方法
1.怎样将元素添加到Map集合中.(*****)
声明: public Object put(Object key,Object value)
作用:向Map集合中添加key与value,
注意:如果key值重复,它会将原本的映射关系破坏,
用新的元素将旧的元素替换,而返回值就是旧的元素.
2.clear
声明:public void clear();
作用:清空集合
3.size
声明:public int size();
作用:得到集合的长度()
4.containsKey containsValue
声明: public boolean containsKey(Object key)
public boolean containsValue(Objectvalue)
作用:判断Map集合中是否包含指定的key或value
5.根据key取得value get
声明:public Object get(Object key)
作用:根据指定的key值,得到对应的value。
注意:如果没有映射关系,返回的是null.
6.remove
声明 public Object remove(Object key)
作用:根据key删除映射关系.
返回值返回的是这个key对应的value值
7.values
声明:publicCollection values();
作用:得到Map集合中的所有的value的值的一个Collection集合。
Map集合的遍历操作
1.使用keySet
1.通过Map的keySet方法得到的是key的Set视图.
2.通过Iterator对Set集合进行迭代,将Map中的所有的key得到了
3.通过Map的get方法,根据key得到对应的value.
2.使用entrySet
1.通过Map的entrySet方法得到的是key-value(其实就是Entry类型)映射的Set视图
2.通过Iterator得到Set集合中的所有的Entry对象.
3.通过Entry对象的getKey getValue方法得到Map集合中的所有的key与value.
Map集合与Collection集合的区别
1.Map是双列集合 Collection是单列集合
2.Map集合存储是使用put方法
Collection存储使用的是add方法.
3.Map集合不能直接使用迭代器遍历.
使用keySet或entrySet方法,得到一个Set集合,在使用迭代器将Map集合中的元素迭代出来。 Collection取值使用迭代器 Iterator
HashMap
HashMap
HashMap允许null值与null键,线程不安全。
它的底层实现是基于hash表的。
HashMap怎样保证其key值不重复?
使用元素的hashCode方法与equals方法保证.
Hashtable
Hashtable不允许null值null键,它是线程安全。
TreeMap
它的底层实现使用的二叉树。它也是线程不安全的。
它怎样保证key的唯一性?
1.自然顺序
2.比较器
与我们之前讲过的TreeSet一样的原理.
Map集合总结
Map 双列集合
|-----HashMap 底层使用hash表实现,它允许null值,null键,线程不安全。
HashMap使用元素的hashCode与equals方法来保证key的唯一。
|------LinkedHashMap
它保证了装入时的key的顺序与取出时key的顺序一样。
|-----Hashtable 它与HashMap的区别,除了不能null值,null键,线程安全。其它一样。
|------Properties
它是对配置文件进行映射的。
在早期开发中,经常的使用这样原的文件进行配置。
|-----TreeMap 底层实现二叉树,它线程不安全。
它使用 自然顺序与比较器保证 key的唯一.
怎样选择使用什么集合
1.判断是存储单列还是双列,这样就可以选择Collection还是Map
2.
2.1Collection
如果没有要求,先List,List下首选ArrayList
如果要求不重复 Set,Set下首先HashSet.
对于LinkedList,TreeSet,它们的使用要根据上体的特性。
2.2Map
首选HashMap,如果要求进行排序,TreeMap.
今日小练习:
将前面日志中的扑克牌程序用集合重写,并提供洗牌的功能.
Package com.itheima.test
import java.util.*;
class Test2{
public static void main(String[] args){
List<Poker> ps=newArrayList<Poker>();
PokerTools.createPoker(ps);
PokerTools.shuffle(ps);
PokerTools.show(ps);
}
}
//关于扑克的一些操作
class PokerTools{
//生成扑克方法
public static void createPoker(List<Poker> ps){
for(int i=0;i<GlobalPoker.cs.length;i++){
for(int j=0;j<GlobalPoker.ns.length;j++){
ps.add(newPoker(GlobalPoker.cs[i],GlobalPoker.ns[j]));
}
}
}
//洗牌的方法
public static void shuffle(List<Poker> ps){
Random ran=newRandom();
for(inti=0;i<ps.size();i++){
intn=ran.nextInt(ps.size());
Poker p1=ps.get(i);
Poker p2=ps.get(n);
ps.set(i,p2);
ps.set(n,p1);
}
}
//显示扑克牌的方法
public static void show(List<Poker> ps){
for(inti=0;i<ps.size();i++){
if(i%GlobalPoker.ns.length==0){
System.out.println();
}
System.out.print(ps.get(i)+" ");
}
}
}
//这个类中定义的是一个常量
class GlobalPoker{
public static final String[] cs={String.valueOf((char)3),String.valueOf((char)4),String.valueOf((char)5),String.valueOf((char)6)};
public static final String[] ns={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
}
class Poker{
String color;
String number;
public Poker(){}
public Poker(String color,String number){
this.color=color;
this.number=number;
}
// 重写toString方法
public String toString(){
return color+number;
}
}