首页 > 代码库 > 黑马程序员——Java基础——集合类
黑马程序员——Java基础——集合类
第一讲 集合
一、集合的概念:
集合时一种容器,长度可变,可以存储任意类型的对象,基本数据类型也能够装入,是因为其内部是先自动装箱包装成包装类对象,然后存入集合的;
对比数组:也是容器,长度固定,只能存储基本数据类型
二、集合的分类
主要掌握的集合:
Collection
List:
|--ArrayList:底层的数据结构使用的是数组结构;查询快,增删慢,不同步
|-LinkedList:底层的数据结构使用的是链式结构;查询慢,增删快
|-Vector:底层数组结构:同步
Set:
|——HashSet:底层数据结构式哈希表。不同步,判断依据是hashCode值,然后是equals
|——TreeSet:底层数据位2查数,判断依据是compareTo和hashCode
还有LinkedHashSet
Map
|-HashMap:哈希表,hashCode,equals
|-TreeMap:二叉树,compareTO,hashCode
还有Hashtable 和LinkedHashMap
三、集合Collection的常用方法
1、常用方法:
add(obj):添加元素
get(index):获得指定位置的元素
size():获得集合的长度
add(index,obj):向指定位置添加一个元素
set(index,obj):将指定位置的元素替换
remover(index):删除指定位置的元素,并返回删除元素
remove(obj):删除集合中包含obj对象
2、迭代集合:迭代器Iterator
- a.for循环: 从0循环到集合的size()-1, 每次获取其中一个
- b.迭代器: 调用iterator()方法获取迭代器, 使用hasNext()判断是否包含下一个元素, 使用next()获取下一个元素
- c.增强for循环: for (类型 变量名 : 容器) { 循环体 } 容器中有多少个元素就执行多少次循环体, 每次循环变量指向容器中不同的元素
第一种打印方式:省资源
for(Iterator iter = a.iterator();iter.hasNext(); )
{
System.out.println(iter.next());
}
第二种打印方式:直观
Iteratoriter = a.iterator();
while(iter.hasNext())
{
System.out.println(iter.next());
}
3、迭代时删除的问题
- a.for循环: 删除时由于后面的元素会向前移动, 所以删除之后循环变量要--
- b.迭代器: 要删除元素时必须使用Iterator中的remove()否则会抛出异常
- c.增强for循环: 不能删除
扩展:迭代的结构由来
要访问集合内部的元素,就需要把取出方法(迭代)定义为内部类;
而根据每个容器的数据结构不同,所抽取动作细节不同,把共性内容抽取:
即:判断和取出,将这些共性抽取为Iterator。然后通过它对外提供的方法
iterator()进行迭代:有next()取出,hasNext()判断
第二讲 List
一.List在集合中的分类与特点
Collection
List:
|--ArrayList:底层的数据结构使用的是数组结构;查询快,增删慢,不同步
|-LinkedList:底层的数据结构使用的是链式结构;查询慢,增删快
|-Vector:底层数组结构:同步
特殊方法:
indexOf(元素)返回角标
subList(start,end):取头和不包括尾的集合
ListIterator:独有的迭代器
iterator:只有hasNext()、next(),remove()
而ListIterator有独有方法:add(obj)、set(obj)修改、hasPrevious()逆向判断有没有、previous(),取出一个元素
二、List三个儿子的特点
(1)ArrayList(存储字符串和自定义对象)
ArrayList存储字符串并删除重复值;
1 import java.lang.*; 2 import java.util.*; 3 /*需求:使用ArrayList添加字符串元素,并提出重复项 4 * 原理:添加一个临时容器,在迭代原集合,临时集合包含时才添加到临时集合 5 6 */ 7 public class ArrayListDemo { 8 public static void main(String[] args){ 9 List<String> list=new ArrayList<String>();10 list.add("水音01");11 list.add("水音02");12 list.add("水音03");13 list.add("水音04");14 list.add("水音04");15 System.out.println(list);16 17 zouni(list); 18 System.out.println(list);19 } 20 private static List zouni(List<String> list) {21 // 迭代22 Iterator<String> it=list.iterator();23 List<String> al=new ArrayList<String>();24 while(it.hasNext()){ 25 String line=it.next();//使用迭代就不需要强转26 if(!(al.contains(line))){27 al.add(line);28 }29 }30 return al;31 }32 }
ArrayList添加自定义的对象:
1 mport java.lang.*; 2 import java.util.*; 3 /*需求:使用ArrayList添加字符串元素,并提出重复项 4 * 原理:添加一个临时容器,在迭代原集合,临时集合包含时才添加到临时集合 5 由于contains判断依据是equals所以我在自定义的类中复写equals 6 */ 7 8 class Student{ 9 private String name;10 private int age;11 Student(String name,int age){12 this.name=name;13 this.age=age;14 }15 public String getName() {16 return name;17 }18 19 public int getAge() {20 return age;21 }22 public boolean equals(Object obj) {23 if (!(obj instanceof Student)){24 return false;25 }26 Person p=(Person)obj;27 return this.name.equals(name)&&this.age==age;28 }29 30 }31 public class ArrayListDemo {32 public static void main(String[] args){33 ArrayList<Student> al=new ArrayList<Student>();34 35 al.add(new Student("shuiyin",35));36 al.add(new Student("shuiyin",25));37 al.add(new Student("shuiyin",15));38 al.add(new Student("shuiyin",15));39 40 al=(ArrayList<Student>) zouni(al);41 42 Iterator<Student> it=al.iterator();43 while(it.hasNext()){44 System.out.println(it.next());45 }46 47 } 48 49 private static List zouni(ArrayList<Student> list) {50 // 迭代51 Iterator<Student> it=list.iterator();52 List<Student> al=new ArrayList<Student>();53 while(it.hasNext()){ 54 Object obj=it.next();55 if(al.contains(obj)){56 al.add((Student) obj);57 }58 }59 return al;60 }61 }
(2)Vector(存储字符串和自定对象)
有自己特色的变量迭代(enumeration)
同步,由于不方面已经被ArrayList取得
(3)LinkedList(存储字符串和对象)
有自己特色的操作功能主要指可以很方面的增删取头尾部分的元素
模拟堆栈和队列
1 LinkedList<String> l=new LinkedList(); 2 l.addFirst("shuiyin01"); 3 l.addFirst("shuiyin02"); 4 l.addFirst("shuiyin03"); 5 l.addFirst("shuiyin04"); 6 l.addFirst("shuiyin05"); 7 // 堆栈 8 stack(l); 9 // 队列10 queque(l);11 }12 13 private static void queque(LinkedList<String> l) {14 while(!l.isEmpty()){15 System.out.print(l.removeLast());16 }17 18 }19 20 private static void stack(LinkedList<String> l) {21 while(!l.isEmpty()){22 System.out.print(l.removeFirst());23 }24 }25 26 }
扩展知识:泛型(理解)
(1)泛型是一种明确类型房子创建对象或者调用方法时才去明确的特殊的类型;
(2)格式:
<数据类型>引用数据类型
(3)好处:
A:解决莫名的黄色问题
B:把运行期间的转换异常给提前到编译期间
C:优化了程序设计,不需要强转
(4)泛型的前世今生:
A泛型类 B泛型方法 C泛型接口
(5)在API中的类或者接口有跟着<>就是能添加泛型的
第三讲 Set
一、Set的概念
colection
|-Set:不可重复,无索引,无序()(注意:Set集合都要求不可重复的,所以如何做到不可重复是这里要掌握的)
|——HashSet:底层数据结构式哈希表。不同步,判断依据是hashCode值,然后是equals
|——LinkedHashSet 原理相同,除了去重复之外还能保留存储的顺序
|——TreeSet:底层数据位2查数,判断依据是compareTo和hashCode
还有LinkedHashSet
二、 HashSet
1、Hashset的原理:
Set集合都是需要去除重复值的,但每一次添加都需要和所有原本的元素比较的话,效率太慢了;
所以发明了一种hashCode算法,每个值对应一个放值的位置,当添加新的元素时,只需要把它先转换为HashCode,再
寻找该位置有没有这个值,有则不添加,没有则添加;
这里大大减少了比较的次数;
2、将自定义的对象存入HashSet取重复
自定义的类中必须重新hashCode()和equals(方法
hashCode():属性相同的对象返回值必须相同,属性不同返回值不同;
equals():属性相同返回true,不同返回false
1 class Student{ 2 private String name; 3 private int age; 4 Student(String name,int age){ 5 this.name=name; 6 this.age=age; 7 } 8 public String getName() { 9 return name;10 }11 12 public int getAge() {13 return age;14 }15 public boolean equals(Object obj){16 if(!(obj instanceof Student)){17 return false;18 }19 Student s=(Student)obj;20 return this.name.equals(s.name)&&this.age==age;21 }22 23 public int hashCode(){24 return this.name.hashCode()*31+this.age*2;25 }26 27 28 }29 public class ArrayListDemo {30 public static void main(String[] args){31 HashSet<Student> al=new HashSet<Student>();32 33 al.add(new Student("shuiyin",35));34 al.add(new Student("shuiyin",25));35 al.add(new Student("shuiyin",15));36 al.add(new Student("shuiyin",15));37 al.add(new Student("shuiyin",15));38 39 Iterator<Student> it=al.iterator();40 while(it.hasNext()){41 Student s=it.next();42 System.out.println(s.getName()+"---"+s.getAge());43 }44 } 45 }
三、迭代在List和Set的总结
1.List
*可以使用普通for循环,然后使用get获取
*使用迭代器Iterator中的方法iterator()方法,配合hasNext,next()方法获取;
*List独有的的迭代器ListIterator,有独有方法ListIterator有独有方法:
add(obj)、set(obj)修改、hasPrevious()逆向判断有、previous(),逆向取出一个元素
*Vector集合还可以有枚举enumeration的hasElements()和nextElement()方法,基本淘汰
2.Set
*调用iterator()方法,使用hasNext()和next()方法,注意自定义类需要复写equals和hashCode()
*增加for循环,只要可以使用iterator 的类都可以使用
一、TreeSet
1.TreeSet的原理:
a、底层的数据结构为二叉树结构(红黑树结构)
b)可对Set集合中的元素进行排序,是因为:TreeSet类实现了Comparable接口,该接口强制让增加到集合中的对象进行了比较,需要复写compareTo方法,才能让对象按指定需求(如人的年龄大小比较等)进行排序,并加入集合。
注意:自定义的类要实现Comparable接口;
使用方法:
自然顺序:
存入的对象提升为comparable类型
调用对象的conpareTo()方法;
根据compareTo()方法返回的结果进行存储
1 import java.util.*; 2 /*需求:使用TreeSet添加字符串元素,并提出重复项 3 TreeSet比较使用的是compareTo()方法 4 */ 5 6 class Student implements Comparable{ 7 private String name; 8 private int age; 9 Student(String name,int age){10 this.name=name;11 this.age=age;12 }13 // 需要复写compareTo()使得比较结构-1,0,1,比较年龄在比较名字compareTo14 public int compareTo(Object obj){15 if(!(obj instanceof Student)){16 throw new RuntimeException("类型不对啊!");17 }18 Student s=(Student)obj;19 if(this.age==s.age){20 return this.name.compareTo(s.name);21 }22 return new Integer(this.age).compareTo(new Integer(s.age));23 // 可以return this.age-s.age;上面这样可以保证结果是-1,124 }25 26 public String getName() {27 return name;28 }29 30 public int getAge() {31 return age;32 }33 34 35 36 }37 public class ArrayListDemo {38 public static void main(String[] args){39 TreeSet<Student> al=new TreeSet<Student>();40 41 al.add(new Student("shuiyin",35));42 al.add(new Student("shuiyin",25));43 al.add(new Student("shuiyin",15));44 al.add(new Student("shuiyin",15));45 al.add(new Student("shuiyin",15));46 47 Iterator<Student> it=al.iterator();48 while(it.hasNext()){49 Student s=it.next();50 System.out.println(s.getName()+""+s.getAge());15 }16 } 17 }18 19 //定义一个比较器哦,以性命的长度作为主要比较20 class myCompare implements Comparator<Student>{21 22 public int compare(Student s1, Student s2) {23 int num=s1.getName().length()-s2.getName().length();24 // 相同是比较CompareTo25 if(num==0){26 return s1.getName().compareTo(s2.getName());27 }28 return num;29 }30 31 }
总结;
List使用equals做比较;HashSet使用hashCode然后equals做比较;
而TreeSet使用接口中Camparable中的方法做比较(需要复写compareTo,然后equals)
同时TreeSet还拥有比较器作为集合参数做比较,该比较器需要实现Comparator,同时复写compare方法;
比较器优先级大于自定义于类里面的比较方法
第四讲 Map
Collection
List:
|--ArrayList:底层的数据结构使用的是数组结构;查询快,增删慢,不同步
|-LinkedList:底层的数据结构使用的是链式结构;查询慢,增删快
|-Vector:底层数组结构:同步
Set:
|——HashSet:底层数据结构式哈希表。不同步,判断依据是hashCode值,然后是equals
|——TreeSet:底层数据位2查数,判断依据是compareTo和hashCode
还有LinkedHashSet
Map
|-HashMap:哈希表,比较的方法:hashCode,equals
|-TreeMap:二叉树,比较的方法:compareTO,hashCode
还有Hashtable 和LinkedHashMap
1)概述
Map集合与Collection集合是同等级的,一次存两个对象(键值对)
Map<K,V>集合时一个借口,K-key代表键,V-Value代表值;
2)该集合存储键值对;保证唯一性的方法是键值;
3)常用的方法: 相当于Collection
*put():存入一堆键值 ~相对于add()
*get()根据Key返回Value ~相对于get(index)
*containsKey();判断有木有指定的键
*containsValue():判断有木有指定的值
*remove(K):删除指定键的元素
*size()Map的长度
重点掌握:
Set<K> keySet();取出Map中的key,组成Set集合,通过这样迭代所有元素
Set<Map,Entry<K,V>> entrySet();取出Map中key和value的关系,这个关系的数据类型是:Map.Entry
其实。Entry也是一个接口,它是Map接口中的一个内部接口;
实例:KeySet法
1 /*需求:使用keySet()方法迭代HashMap集合的模拟 2 * 3 * 1)先调用keySet()方法从Map集合中获得所有的key组合成一个Set集合 4 * 2)迭代Set集合可以得到每一个Key; 5 * 3)然后在调用get()方法得到每一个Value 6 * 7 * 注意:假如是自定义的类,HashMap说明需要复写hashCode()和equals 8 * 9 */10 import java.util.*;11 //描述学生12 class Student implements Comparable<Student>{//实现这个是为了集合类TreeSet使用13 private String name;14 private int age;15 Student(String name,int age){16 this.name=name;17 this.age=age;18 }19 public String getName() {20 return name;21 }22 23 public int getAge() {24 return age;25 }26 // 复写equals27 public boolean equals(Object obj) {28 if (!(obj instanceof Student)){29 return false;30 }31 Student p=(Student)obj;32 return this.name.equals(name)&&this.age==age;33 }34 // 复写hashCode35 public int hashCode(){36 return name.hashCode()+age*31;37 }38 39 public int compareTo(Student s) {//已经明确指明是学生类所以不用obj40 int num=this.age-s.age;41 if(num==0)42 return this.name.compareTo(s.name);43 return num;44 }45 46 47 public String toString(){48 return name+"---"+age;49 } 50 }51 52 53 public class SetDemo {54 public static void main(String[] args){55 HashMap<Student,String> hm=new HashMap<Student,String>();56 57 hm.put(new Student("shuiyin4",23), "beji");58 hm.put(new Student("shuiyin3",13), "zs");59 hm.put(new Student("shuiyin2",43), "sz");60 hm.put(new Student("shuiyin1",33), "gz");61 62 ketSet(hm);63 }64 65 private static void ketSet(HashMap<Student, String> hm) {66 // 使用keySet迭代法67 Iterator<Student> it=hm.keySet().iterator();68 69 while(it.hasNext()){70 Student key=it.next();//得到键71 String value=http://www.mamicode.com/hm.get(key);72 System.out.println(key+"::"+value);73 }74 75 } 76 }
实例:entrySet法
1 public class SetDemo { 2 public static void main(String[] args){ 3 HashMap<Student,String> hm=new HashMap<Student,String>(); 4 5 hm.put(new Student("shuiyin4",23), "beji"); 6 hm.put(new Student("shuiyin3",13), "zs"); 7 hm.put(new Student("shuiyin2",43), "sz"); 8 hm.put(new Student("shuiyin1",33), "gz"); 9 10 ketSet(hm);11 entrySet(hm);12 }13 14 private static void entrySet(HashMap<Student, String> hm) {15 Iterator<Map.Entry<Student,String>> it=hm.entrySet().iterator();16 while(it.hasNext()){17 Map.Entry<Student, String> me=it.next();18 Student key=me.getKey();19 String value=http://www.mamicode.com/me.getValue();20 System.out.println(key+"**"+value);21 }22 }
HashMap的总结
HashMap存入过程 在使用HashMap存键值对的时候,先调用Key对象的hashCode()方法计算
如果没有哈希值相同的Key的对象,键值就存入;
如果哈希值相同,则用equals比较
根据结果存入元素
4)LinkedHashMap
HashMap的子类、算法相同但保留了存储的顺序
5)TreeMap
在使用TreeMap存储键值键值对时候,会使用Key对象和集合中已经存在的Key对象比较,确定在二叉树的位置
比较的方式和TreeSet指定的方式相同,使用自定义类中implements Comparable或者比较器Comparator
6)Hashtable
类似hashMao,线程安全通报,效率低,不育系null值和null键
7)Map集合的应用和扩展
实例:获取一个字符串字母出现的次数:
1 /*思路:1、将字符串转换为字符数组 2 * 2、定义一个TreeMap集合,用于字母和字母出现的次数 3 * 3、用数组取变量集合,日过集合有该字母则次数加1,没有集合中则存入 4 * 4、将TreeMap集合中的元素转换为字符 5 */ 6 import java.util.*; 7 public class CharCount { 8 public static void main(String[] args){ 9 String s="afsdgdsghfgd";10 System.out.println("各字母出现次数"+charCout(s));11 12 }13 14 private static String charCout(String s) {15 char[] cha=s.toCharArray();16 // 定义一个TreeMap集合,因为TreeMap集合会给键自动排序,compareTo方法与字母排序相同17 TreeMap<Character,Integer> tm=18 new TreeMap<Character,Integer>();19 20 int count=0;//用于计数21 22 for(int x=0;x<cha.length;x++){23 if(!(cha[x]>=‘a‘&&cha[x]<=‘z‘||cha[x]>=‘A‘&&cha[x]<=‘Z‘))24 continue;//如果不是字母,就不管他25 Integer value=http://www.mamicode.com/tm.get(cha[x]);//获取对饮key的值26 if(value!=0){27 count=value;//每一次都先获取上一次该key对应的value,继而加128 }29 count++;30 tm.put(cha[x], value);31 count=0;//复位计数变量32 33 }34 35 StringBuilder sb=36 new StringBuilder();37 // 遍历38 for(Iterator<Character> it=tm.keySet().iterator();it.hasNext();){39 Character ch=it.next();40 Integer value=http://www.mamicode.com/tm.get(ch);41 sb.append(ch+"("+value+")");42 }43 return sb.toString();//返回字符串44 }45 }
扩展知识,集合镶嵌集合:
每个学生有学号和姓名,它有事一个班集合的成员,一个班又在一个学校内
1 /*在Map的扩展中,很多应用是一对多的映射,这可以通过镶嵌的形式将多个映射定义到 2 * 一份大集合中,再将该集合用一个更大的集合处理 3 * 思路:一个学校的集合有班名和对应的班集合,班集合有对应学生(包括学号和姓名) 4 * 所以以成对形式存储,使用HashMap 5 */ 6 import java.util.*; 7 public class CharCount { 8 public static void main(String[] args){ 9 HashMap<String,HashMap<String,String>> wlg =10 new HashMap<String,HashMap<String,String>>();11 HashMap<String,String> lxy =12 new HashMap<String,String>();13 HashMap<String,String> gl =14 new HashMap<String,String>();15 // 学校添加班级,班级名和班组集合16 wlg.put("lxy",lxy);17 wlg.put("gl",gl);18 // 班组添加学生19 lxy.put("001","水音");20 lxy.put("002","秀萍");21 gl.put("001","靖显");22 lxy.put("002","道上");23 // 遍历学校24 getAllInfo(wlg);25 }26 27 private static void getAllInfo(HashMap<String, HashMap<String, String>> wlg) {28 Iterator<String> it=wlg.keySet().iterator();29 30 while(it.hasNext()){31 HashMap<String,String> hm=wlg.get(it.next());32 getStudent(hm);33 }34 35 36 }37 38 private static void getStudent(HashMap<String, String> hm) {39 for(Iterator<String> it=hm.keySet().iterator();it.hasNext();){40 String key=it.next();41 String value=http://www.mamicode.com/hm.get(key);42 System.out.println(key+"+"+value);43 }44 }45 46 }
黑马程序员——Java基础——集合类