Java基础<九>_集合(上)
2013-09-14 21:50
721 查看
集合(上)
一、Collection
1.1、集合的概述
根据面向对象的思想,数据多了就用对象来存储;对象多了,就用数组或者集合来存储。数组虽然可以存储对象,但长度不可变,类型固定,有很大的局限性;集合长度可变,类型不固定。正因为集合克服了数组的局限性,所以对象的存储大多数存在集合中。
因为底层的数据结构不同,所以集合可以分为很多种,但根据共性抽取的原则,可以把多种不同的集合不断地向上抽取。Collection接口就是不断抽取而成的,它可以分为List和Set两大接口。
List:元素有序,元素可以重复,有索引;
Set:元素无序(存入取出无序),元素不可重复。
Collection中有抽取了一些共性的方法,例如:add(Object obj):添加元素到集合中。
注意:集合中存储的都是对象的引用,也就是地址,并非对象本身。Java中的集合框架如下图所示:
![](http://img.blog.csdn.net/20130914213533640?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbGl5dWFucQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
迭代器:迭代器就是取出集合元素的方式。由于每个集合内部的数据结构不同,取出方式也就有所不同,但该怎么取出元素,只有集合本身最清楚,所以迭代器应该定义在集合的内部,成为内部类或者内部接口。但每种集合元素的取出方式都有一些共性,比如:内容判断、取出等,那么就将这些共性抽取形成一个接口:Iterator。
在java中,形成了Iterator接口后,取出不同集合的元素就在不同集合的内部实现;
那么该如何获取取出对象呢?通过对外提供的方法iterator()即可,这就是迭代器的基本原理。
二、List
List是Collection接口中的一个重要子接口,实现List接口的子类有很多,但比较重要的有Vector、ArrayList和LinkedList三个,下面主要介绍的也就是这三个。
ArrayList:底层的数据结构是数组,查询速度快,但增删操作稍慢,线程不同步。
LinkedList:底层的数据结构是链表,查询速度稍慢,但增删操作很快,线程不同步。
Vector:底层的数据结构是数组,线程同步,已经被ArrayList替代。
List接口中,有自己特有的方法,注意:凡是可以操作角标的方法都是该体系特有的方法。
增:add(index,element); addAll(index,Collection);
删:remove(index);
改:set(index,element);
查:get(index);SubList(from,to);ListIterator()。
List集合特有的迭代器:ListIterator。ListIterator是Iterator的子接口。
在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生异常。所以在迭代时,只能用迭代的方式操作元素,可是Iterator中的方法是有限的,只能对元素进行判断、取出、删除等操作。
如果想进行其他的操作如添加、修改等,必须使用ListIterator,该接口只能通过List集合中的ListIterator()方法获取。
LinkList特有方法:
addFirst();addlast();添加元素;
getFirst();getLast(); 获取但不删除;
removeFirst();removeLast():获取但删除。
JDK1.6出现了替代方法:
offerFirst();offerLast();添加元素;
peekFirst();peekLast()获取但不删除;
pollFirst();pollLast()获取但删除。
在List集合中,判断元素是否相同,调用的是元素的equals()方法;remove(),contains()等方法的底层也是调用了equals()方法。
注意:List集合中开发多用ArrayList,因为集合中一般都是查询的多。
下面代码体现:
1、将自定义的对象作为元素存到ArrayList集合中,并去除重复的元素
2、使用LinkedList模拟一个堆栈或者队列数据结构
三、Set
Set中的元素无序(存入和取出无序),元素不可以重复;Set是Collection接口中一个重要的子接口;实现Set接口的子类有很多,但比较重要的有HashSet、TreeSet两个。
HashSet:底层数据结构是哈希表。HashSet通过调用元素自身的hashCode()、equals()方法来保证元素的唯一性。
如果元素的hashCode()返回的值不同,则直接认为两个元素不是同一个元素;否则,继续判断元素的equals()方法,如果返回值是false,则认为两个元素不是同一个元素;返回值为true,则认为两个元素是同一个元素,注意:若哈希值不一样,不会继续判断equals()方法。
所以:如果自定义的对象要存储到HashSet集合中,必须覆盖对象自身的hashCode()方法和equals()方法。
TreeSet:HashSet集合可以保证元素的唯一性,但不能保证元素的有序性;而TreeSet集合既可以保证元素的唯一性,也可以保证元素在集合中存储的有序性。
TreeSet保证元素有序性有两种方式:让元素自身基本具备比较性、让TreeSet集合本身具备比较性。
1、让元素自身具备比较性:Copareable接口可以让元素具备比较性,实现该接口的类必须实现CompareTo()方法;所以,要想让元素自身具备比较性,需要实现Comparable接口,复写compareTo方法,即可。
2、让TreeSet集合自身具备比较性:当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就需要让TreeSet具备比较性。可以定义一个类,实现Comparator接口,并且覆盖compare()方法,称之为比较器;然后将比较器对象作为参数传递给TreeSet集合的构造函数,即可。
TreeSet集合底层数据结构是二叉树,当元素进入二叉树时,可以减少比较次数,提高效率。
下面代码体现:
1、往HashSet集合中存入自定义对象
2、往TreeSet集合中存储自定义对象学生,按照学生的年龄进行排序
3、按照字符串长度进行排序
四、泛型
泛型:泛型是JDK1.5版本以后出现的新特性,是一种类型安全机制,专门用于解决安全问题;泛型常常出现在集合框架中。
好处1:集合中可以存储任意类型的元素,也就是说一个集合中可以存储两个或者以上不同类型的元素,但操作类型的方法底层在调用不同类型元素的方法时,往往会出现问题;所以:程序员必须主观控制存入集合中的类型,往往编译能通过,但运行时会出现ClassCastException异常。泛型的出现,可以将运行时期出现的ClassCastException转移到了编译时期,方便于程序员解决问题,让运行时问题减少,安全。
好处2:避免了强制类型转换带来的麻烦。
泛型格式:通过<>来定义要操作的引用类型,当使用集合时,将集合中要存储的类型写到<>中即可。
泛型的定义:当集合中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型来完成扩展。
定义在类上的泛型,在整个类中有效,称之为:带泛型的类。
定义在方法上的泛型,在整个方法体中有效,称之为:带泛型的方法。
注意:静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
泛型的限定:
?:通配符,也可以理解为占位符;
?extends E:可以接收E类型或者E的子类型,上限;
?super E:可以接收E类型或者E的父类型,下限。
下面代码体现:
1、演示泛型类、泛型方法、静态泛型方法
2、上限的使用,举例说明
3、下限的使用,举例说明
五、Map
Map集合:Map不同于Collection,Collection中存储的是单个元素,而Map中存储的是键值对,一对一对往里存储,并要保证唯一性。
Map集合中的共性方法:
1、添加:put(K key, V value);putAll(Map<? extendsK, <? extends K> m);
2、删除:clear();remove(Object key);
3、判断:containsValue(Object value);containsKey(Objectkey);isEmpty();
4、获取:get(Object key);size();value();entrySet();keySet()。
实现Map接口的子类有很多,但重要的有Hashtable、HashMap、TreeMap三个。下面主要介绍这三个。
Hashtable:底层是哈希表数据结构,不可以存入null键null值,线程同步,效率低;
HashMap:底层是哈希表数据结构,允许使用null值和null键,线程不同步,效率高;
TreeMap:底层是二叉树数据结构,线程不同步,可以用于给map集合中的键进行排序。
Map集合的两种取出方式:
1、keySet:将map中所有的键存入到Set集合,因为Set具备迭代器,所以可以迭代方式取出所有的键,再通过get()方法获取每一个键对应的值。
2、Set<Map.Entry<K,V>>:将map集合中的映射关系存入到set集合 中,而这个关系就是Map.Entey。Map.Entry:其实Entry也是 一个接口,它是Map接口中的一个内部接口。
总之:Set底层就是使用了Map集合;Map集合的取出原理:将map集合转成set集合,再通过迭代器取出。
下面代码体现:
1、存储:学生Student对应一个地址String,姓名和年龄相同视为同一个学生
2、对学生对象的姓名进行升序排序
3、获取一个字符串中字母出现的次数,希望打印结果为:a(1)b(2)...
一、Collection
1.1、集合的概述
根据面向对象的思想,数据多了就用对象来存储;对象多了,就用数组或者集合来存储。数组虽然可以存储对象,但长度不可变,类型固定,有很大的局限性;集合长度可变,类型不固定。正因为集合克服了数组的局限性,所以对象的存储大多数存在集合中。
因为底层的数据结构不同,所以集合可以分为很多种,但根据共性抽取的原则,可以把多种不同的集合不断地向上抽取。Collection接口就是不断抽取而成的,它可以分为List和Set两大接口。
List:元素有序,元素可以重复,有索引;
Set:元素无序(存入取出无序),元素不可重复。
Collection中有抽取了一些共性的方法,例如:add(Object obj):添加元素到集合中。
注意:集合中存储的都是对象的引用,也就是地址,并非对象本身。Java中的集合框架如下图所示:
迭代器:迭代器就是取出集合元素的方式。由于每个集合内部的数据结构不同,取出方式也就有所不同,但该怎么取出元素,只有集合本身最清楚,所以迭代器应该定义在集合的内部,成为内部类或者内部接口。但每种集合元素的取出方式都有一些共性,比如:内容判断、取出等,那么就将这些共性抽取形成一个接口:Iterator。
在java中,形成了Iterator接口后,取出不同集合的元素就在不同集合的内部实现;
那么该如何获取取出对象呢?通过对外提供的方法iterator()即可,这就是迭代器的基本原理。
二、List
List是Collection接口中的一个重要子接口,实现List接口的子类有很多,但比较重要的有Vector、ArrayList和LinkedList三个,下面主要介绍的也就是这三个。
ArrayList:底层的数据结构是数组,查询速度快,但增删操作稍慢,线程不同步。
LinkedList:底层的数据结构是链表,查询速度稍慢,但增删操作很快,线程不同步。
Vector:底层的数据结构是数组,线程同步,已经被ArrayList替代。
List接口中,有自己特有的方法,注意:凡是可以操作角标的方法都是该体系特有的方法。
增:add(index,element); addAll(index,Collection);
删:remove(index);
改:set(index,element);
查:get(index);SubList(from,to);ListIterator()。
List集合特有的迭代器:ListIterator。ListIterator是Iterator的子接口。
在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生异常。所以在迭代时,只能用迭代的方式操作元素,可是Iterator中的方法是有限的,只能对元素进行判断、取出、删除等操作。
如果想进行其他的操作如添加、修改等,必须使用ListIterator,该接口只能通过List集合中的ListIterator()方法获取。
LinkList特有方法:
addFirst();addlast();添加元素;
getFirst();getLast(); 获取但不删除;
removeFirst();removeLast():获取但删除。
JDK1.6出现了替代方法:
offerFirst();offerLast();添加元素;
peekFirst();peekLast()获取但不删除;
pollFirst();pollLast()获取但删除。
在List集合中,判断元素是否相同,调用的是元素的equals()方法;remove(),contains()等方法的底层也是调用了equals()方法。
注意:List集合中开发多用ArrayList,因为集合中一般都是查询的多。
下面代码体现:
1、将自定义的对象作为元素存到ArrayList集合中,并去除重复的元素
package itheima.day14; import java.util.ArrayList; import java.util.Iterator; //需求: // 将自定义对象作为元素存到ArrayList集合中,并去除重复元素 // 比如:人对象,同姓名同年龄,视为同一个人 public class ArrayListTest2 { public static void main(String[] args) { ArrayList al = new ArrayList(); // 添加元素 al.add(new Person("zhangsan",15)); al.add(new Person("zhangsan1",16)); al.add(new Person("zhangsan2",17)); al.add(new Person("zhangsan1",16)); al = singleElement(al); // 通过迭代器的方式取出集合中的元素 Iterator it = al.iterator(); while(it.hasNext()){ Object obj = it.next(); Person p = (Person)obj; sop(p.getName()+"::::"+p.getAge()); } } private static ArrayList singleElement(ArrayList al) { // 定义一个临时容器 ArrayList newAl = new ArrayList(); Iterator it = al.iterator(); while(it.hasNext()){ Object obj = it.next(); if(!newAl.contains(obj))//是否包含 newAl.add(obj); } return newAl; } public static void sop(Object obj){ System.out.println(obj); } } //人 class Person{ private String name; private int age; Person(String name,int age){ this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // List集合判断元素是否相同,依据的是元素的equals方法。 // remove(),contains()方法的底层也是调用了equals方法. // 必须覆盖Object中的equals方法,根据自定义的方式判断两个元素是否相同 public boolean equals(Object obj){ if(!(obj instanceof Person)) return false; Person p = (Person)obj; return this.name .equals(p.name) && this.age == p.age; } }
2、使用LinkedList模拟一个堆栈或者队列数据结构
package itheima.day14; import java.util.LinkedList; //使用LinkedList模拟一个堆栈或者队列数据结构*/ //堆栈:先进后出,如同杯子 // 队列:先进先出:如同水管 public class LinkedListTest { public static void main(String[] args) { DuiLie dl = new DuiLie(); dl.myAdd("java01"); dl.myAdd("java02"); dl.myAdd("java03"); dl.myAdd("java04"); while(!dl.isNull()){ sop(dl.myGet()); } } public static void sop(Object obj){ System.out.println(obj); } } //封装一个队列的类 class DuiLie{ // 底层封装一个链表,改造 private LinkedList link; DuiLie(){ link = new LinkedList(); } public void myAdd(Object obj){ link.addFirst(obj); } public Object myGet(){ return link.removeLast();//队列:先进先出 // return link.removeFirst();//如果是堆栈的话,就后进先出 } public boolean isNull(){ return link.isEmpty(); } }
三、Set
Set中的元素无序(存入和取出无序),元素不可以重复;Set是Collection接口中一个重要的子接口;实现Set接口的子类有很多,但比较重要的有HashSet、TreeSet两个。
HashSet:底层数据结构是哈希表。HashSet通过调用元素自身的hashCode()、equals()方法来保证元素的唯一性。
如果元素的hashCode()返回的值不同,则直接认为两个元素不是同一个元素;否则,继续判断元素的equals()方法,如果返回值是false,则认为两个元素不是同一个元素;返回值为true,则认为两个元素是同一个元素,注意:若哈希值不一样,不会继续判断equals()方法。
所以:如果自定义的对象要存储到HashSet集合中,必须覆盖对象自身的hashCode()方法和equals()方法。
TreeSet:HashSet集合可以保证元素的唯一性,但不能保证元素的有序性;而TreeSet集合既可以保证元素的唯一性,也可以保证元素在集合中存储的有序性。
TreeSet保证元素有序性有两种方式:让元素自身基本具备比较性、让TreeSet集合本身具备比较性。
1、让元素自身具备比较性:Copareable接口可以让元素具备比较性,实现该接口的类必须实现CompareTo()方法;所以,要想让元素自身具备比较性,需要实现Comparable接口,复写compareTo方法,即可。
2、让TreeSet集合自身具备比较性:当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就需要让TreeSet具备比较性。可以定义一个类,实现Comparator接口,并且覆盖compare()方法,称之为比较器;然后将比较器对象作为参数传递给TreeSet集合的构造函数,即可。
TreeSet集合底层数据结构是二叉树,当元素进入二叉树时,可以减少比较次数,提高效率。
下面代码体现:
1、往HashSet集合中存入自定义对象
package itheima.day14; import java.util.HashSet; import java.util.Iterator; //往HashSet集合中存入自定义对象 // 人:姓名和年龄相同,那么视为同一个对象 public class HashSetTest { public static void main(String[] args) { HashSet hs = new HashSet(); // 添加元素 hs.add(new Person1("a1",12)); hs.add(new Person1("a2",13)); hs.add(new Person1("a3",14)); hs.add(new Person1("a1",12)); hs.add(new Person1("a4",15)); boolean yes =hs.contains(new Person1("a1",12)); System.out.println(yes); // 迭代器的=方式取出元素 Iterator it = hs.iterator(); while(it.hasNext()){ Person1 p = (Person1)it.next(); System.out.println(p.getName()+"::::"+p.getAge()); } } } //人 class Person1{ private String name; private int age; Person1(String name,int age){ this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // 为了让能够存入HashSet集合中,元素自身必须覆盖hashCode()函数 public int hashCode(){ return name.hashCode()+age*23;//哈希值按照本类的属性进行计算,更合理 } // 为了让能够存入HashSet集合中,元素自身必须覆盖equals()函数 public boolean equals(Object obj){ if(!(obj instanceof Person1)) throw new RuntimeException("哥们,类型错误啦"); Person1 p = (Person1)obj; // 如果姓名、年龄相同,视为同一个人 return this.name .equals(p.name) && this.age == p.age; } }
2、往TreeSet集合中存储自定义对象学生,按照学生的年龄进行排序
package itheima.day15; import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; //需求: // 往TreeSet集合中存储自定义对象学生,按照学生的年龄进行排序 public class TreeSetDemo { public static void main(String[] args) { // new一个比较器对象作为参数传给构造函数,让集合自身具备比较性 // TreeSet ts = new TreeSet(new MyCompare()); // 根据元素自身的排序方式进行排序 TreeSet ts = new TreeSet(); // 添加元素 ts.add(new Student("zhangsan1",23)); ts.add(new Student("zhangsan611",23)); ts.add(new Student("zhangsan2",24)); ts.add(new Student("zhangsan4",25)); ts.add(new Student("zhangsan0",23)); // 通过迭代器方式取出元素 Iterator it = ts.iterator(); while(it.hasNext()){ Student stu = (Student)(it.next()); System.out.println(stu.getName()+":::::"+stu.getAge()); } } } //学生的类 class Student implements Comparable//该接口强制学生对象具有比较性 { private String name; private int age; Student(String name,int age){ this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // 为了存入TreeSet集合中,可以让元素自身具备比较性 public int compareTo(Object obj){ if(!(obj instanceof Student)) throw new RuntimeException("不是学生对象!!!"); Student s = (Student)obj; // 按照年龄排序,年龄相同时,按照姓名的自然顺序比较 if(this.age>s.age) return 1; if(this.age <s.age) return -1; return this.name.compareTo(s.name); } } //让TreeSet集合具备比较性,定义一个比较器 class MyCompare implements Comparator { public int compare(Object o1,Object o2){ if(!(o1 instanceof Student)|| !(o2 instanceof Student)) throw new RuntimeException("不是学生类!!!"); Student s1 =(Student)o1; Student s2 = (Student)o2; // 按姓名的自然顺序排序,当姓名相同时,按年龄排序 int num = s1.getName().compareTo(s2.getName()); if(num==0) return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); return num; } }
3、按照字符串长度进行排序
package itheima.day15; import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; //练习:按照字符串长度进行排序 //字符串自身具备的比较性时按照自然顺序比较的,不是我们想要的, // 所以,必须要让TreeSet集合自身具备比较性 public class TreeSetTest { public static void main(String[] args) { // 让TreeSet集合自身具备比较性,传比较器给构造函数 TreeSet ts = new TreeSet(new StrLenComparator()); // 添加元素 ts.add("abcdef"); ts.add("abcde"); ts.add("abcd"); ts.add("a"); ts.add("abc"); ts.add("abd"); // 取出元素 Iterator it = ts.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } } //定义一个比较器 class StrLenComparator implements Comparator { // 覆盖该方法,具有比较性 public int compare(Object o1,Object o2){ String s1 = (String)o1; String s2 = (String)o2; // 按照自然顺序进行排序,若长度相同,则按照字符串的自然比较顺序排序 if(s1.length()>s2.length()) return 1; if(s1.length()<s2.length()) return -1; return s1.compareTo(s2); } }
四、泛型
泛型:泛型是JDK1.5版本以后出现的新特性,是一种类型安全机制,专门用于解决安全问题;泛型常常出现在集合框架中。
好处1:集合中可以存储任意类型的元素,也就是说一个集合中可以存储两个或者以上不同类型的元素,但操作类型的方法底层在调用不同类型元素的方法时,往往会出现问题;所以:程序员必须主观控制存入集合中的类型,往往编译能通过,但运行时会出现ClassCastException异常。泛型的出现,可以将运行时期出现的ClassCastException转移到了编译时期,方便于程序员解决问题,让运行时问题减少,安全。
好处2:避免了强制类型转换带来的麻烦。
泛型格式:通过<>来定义要操作的引用类型,当使用集合时,将集合中要存储的类型写到<>中即可。
泛型的定义:当集合中要操作的引用数据类型不确定时,早期定义Object来完成扩展,现在定义泛型来完成扩展。
定义在类上的泛型,在整个类中有效,称之为:带泛型的类。
定义在方法上的泛型,在整个方法体中有效,称之为:带泛型的方法。
注意:静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
泛型的限定:
?:通配符,也可以理解为占位符;
?extends E:可以接收E类型或者E的子类型,上限;
?super E:可以接收E类型或者E的父类型,下限。
下面代码体现:
1、演示泛型类、泛型方法、静态泛型方法
package itheima.day15; //泛型类,泛型方法,静态泛型方法的演示 public class GenericDemo4 { public static void main(String[] args) { Demo<String> d = new Demo<String>(); d.show("haha"); d.print_1(new Integer(4)); d.method(new Double(153.652)); } } //类型不确定,定义带泛型的类 class Demo<T>{ // 类的泛型在类中的成员方法上有效 public void show(T t){ System.out.println("Class Generic show::"+t); } // 方法上要操作的类型不确定,定义带泛型的方法 public <Q> void print_1(Q q){ System.out.println("Method Generic show:::"+q); } // 静态方法不可以使用类上的泛型,带泛型的静态方法 public static <W> void method(W w){ System.out.println("Generic static method show:::"+w); } }
2、上限的使用,举例说明
package itheima.day15; import java.util.ArrayList; import java.util.Iterator; //泛型的上限,举例说明 public class GenericDemo6 { public static void main(String[] args) { ArrayList<Person> al = new ArrayList<Person>(); al.add(new Person("abc1")); al.add(new Person("abc2")); al.add(new Person("abc3")); al.add(new Person("abc4")); // printColl(al); ArrayList<Student2> al1 = new ArrayList<Student2>(); al1.add(new Student2("abc---1")); al1.add(new Student2("abc---2")); al1.add(new Student2("abc---3")); al1.add(new Student2("abc---4")); // printColl(ArrayList<? extends Person> al),Student2继承Person,上限 printColl(al1); } // ? extends E:可以接收E类型或者E的子类型,上限 public static void printColl(ArrayList<? extends Person> al){ Iterator<? extends Person> it = al.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } } class Person{ private String name; Person(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "name:::" + name ; } } //学生 class Student2 extends Person implements Comparable<Person>//<? extends E> { public Student2(String name) { super(name); } public int compareTo(Person s){ return this.getName().compareTo(s.getName()); } }
3、下限的使用,举例说明
package itheima.day15; import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; //泛型的下限,举例说明 public class GenericDemo8 { public static void main(String[] args) { // TreeSet(Comparator<? super E> comparator) // E:泛型;Student3:参数化的泛型;Comparator<? super E>:意思是说:可以使用Student3父类的比较器 TreeSet<Student3> ts = new TreeSet<Student3>(new Comp()); // 添加元素 ts.add(new Student3("abc01")); ts.add(new Student3("abc05")); ts.add(new Student3("abc03")); ts.add(new Student3("abc04")); Iterator<Student3> it = ts.iterator(); while(it.hasNext()){ System.out.println(it.next().getName()); } TreeSet<Worker1> ts1 = new TreeSet<Worker1>(new Comp()); // 添加元素 ts1.add(new Worker1("abc----01")); ts1.add(new Worker1("abc----05")); ts1.add(new Worker1("abc----03")); ts1.add(new Worker1("abc----04")); Iterator<Worker1> it1 = ts1.iterator(); while(it1.hasNext()){ System.out.println(it1.next().getName()); } } } //比较器 class Comp implements Comparator<Person2>{ public int compare(Person2 s1,Person2 s2){ return s1.getName().compareTo(s2.getName()); } } //人 class Person2{ private String name; Person2(String name){ this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } //学生类,并继承于人 class Student3 extends Person2{ Student3(String name){ super(name); } } //工人类,并继承于人 class Worker1 extends Person2{ Worker1(String name){ super(name); } }
五、Map
Map集合:Map不同于Collection,Collection中存储的是单个元素,而Map中存储的是键值对,一对一对往里存储,并要保证唯一性。
Map集合中的共性方法:
1、添加:put(K key, V value);putAll(Map<? extendsK, <? extends K> m);
2、删除:clear();remove(Object key);
3、判断:containsValue(Object value);containsKey(Objectkey);isEmpty();
4、获取:get(Object key);size();value();entrySet();keySet()。
实现Map接口的子类有很多,但重要的有Hashtable、HashMap、TreeMap三个。下面主要介绍这三个。
Hashtable:底层是哈希表数据结构,不可以存入null键null值,线程同步,效率低;
HashMap:底层是哈希表数据结构,允许使用null值和null键,线程不同步,效率高;
TreeMap:底层是二叉树数据结构,线程不同步,可以用于给map集合中的键进行排序。
Map集合的两种取出方式:
1、keySet:将map中所有的键存入到Set集合,因为Set具备迭代器,所以可以迭代方式取出所有的键,再通过get()方法获取每一个键对应的值。
2、Set<Map.Entry<K,V>>:将map集合中的映射关系存入到set集合 中,而这个关系就是Map.Entey。Map.Entry:其实Entry也是 一个接口,它是Map接口中的一个内部接口。
总之:Set底层就是使用了Map集合;Map集合的取出原理:将map集合转成set集合,再通过迭代器取出。
下面代码体现:
1、存储:学生Student对应一个地址String,姓名和年龄相同视为同一个学生
package itheima.day16; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; //每个学生都有对应的归属地,学生Student,地址String, // 学生属性:姓名,年龄。注意:姓名和年龄相同视为同一个学生。 // 要保证学生的唯一性 //思路:1描述学生 // 2、定义map容器,学生作为键,地址作为值,存入 // 3、获取map集合中的元素 public class MapTest { public static void main(String[] args) { HashMap<Student,String> hm = new HashMap<Student,String>(); hm.put(new Student("zhangsan01",21), "北京"); hm.put(new Student("zhangsan05",25), "上海"); hm.put(new Student("zhangsan03",23), "广州"); hm.put(new Student("zhangsan02",22), "南京"); hm.put(new Student("zhangsan06",26), "西安"); hm.put(new Student("zhangsan04",24), "桂林"); Set<Student> keySet = hm.keySet(); Iterator<Student> it = keySet.iterator(); while(it.hasNext()){ Student stu = it.next(); String addr = hm.get(stu); System.out.println(stu+"::::"+addr); } } } class Student implements Comparable<Student> { private String name; private int age; Student(String name,int age){ this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String toString(){ return name+"::::"+age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public int compareTo(Student o) { int num = new Integer(this.age).compareTo(new Integer(o.age)); if(num ==0) return this.getName().compareTo(o.getName()); return num; } }
2、对学生对象的姓名进行升序排序
package itheima.day16; import java.util.Comparator; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import itheima.day16.Student; //需求:对学生对象的姓名进行升序排序,。 // 因为数据是以键值对形式存在,所以要使用可以排序的Map集合,TreeMap public class MapTest2 { public static void main(String[] args) { TreeMap<Student,String> tm = new TreeMap<Student,String>(new StuNameComparator()); tm.put(new Student("zhangsan01",21), "北京"); tm.put(new Student("zhangsan005",25), "上海"); tm.put(new Student("zhangsan03",23), "广州"); tm.put(new Student("zhangsan002",22), "南京"); tm.put(new Student("zhangsan06",26), "西安"); tm.put(new Student("zhangsan004",24), "桂林"); Set<Map.Entry<Student,String>> entrySet = tm.entrySet(); Iterator<Map.Entry<Student,String>> it = entrySet.iterator(); while(it.hasNext()){ Map.Entry<Student,String> me = it.next(); Student stu = me.getKey(); String addr = me.getValue(); System.out.println(stu+":::"+addr); } } } class StuNameComparator implements Comparator<Student>{ @Override public int compare(Student s1, Student s2) { int num = s1.getName().compareTo(s2.getName()); if(num == 0) return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); return num; } }
3、获取一个字符串中字母出现的次数,希望打印结果为:a(1)b(2)...
package itheima.day16; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; //练习:获取一个字符串中字母出现的次数,希望打印结果为:a(1)b(2)... //思路:1、将字符串转换成字符数组,因为要对每一个字母进行操作; // 2、定义一个map集合,因为打印结果的字母有顺序,TreeMap; // 3、遍历字符数组,将每一个字母作为键去查map集合,如果返回null, // 存入;如果不是null,则对应的值加1。 // 4、将map集合中的数据变成指定的字符串形式返回。 public class MapTest3 { public static void main(String[] args) { String str ="54653gfghfhvfagfgafsdg"; System.out.println(charCount(str)); } public static String charCount(String str){ char[] chs = str.toCharArray(); TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>(); int count =0; for(int x=0;x<chs.length;x++){ if(!(chs[x]>='a'&& chs[x]<='z' || chs[x]>='A'&&chs[x]<='Z'))//非字母,不存 continue; Integer value = tm.get(chs[x]); if(value!=null) count = value; count++; tm.put(chs[x], count); count=0; } StringBuilder sb = new StringBuilder(); Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet(); Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator(); while(it.hasNext()){ Map.Entry<Character, Integer> me = it.next(); Character ch = me.getKey(); Integer value = me.getValue(); sb.append(ch+"("+value+")"); } return sb.toString(); } }
相关文章推荐
- 黑马程序员 JAVA基础<四> 集合
- Java基础<十一>--->集合之List、Set
- 黑马程序员 Java基础<九>---> 其他对象
- 黑马程序员 Java基础<八>---> 集合-工具类
- 程序员_Java基础之<七>-集合框架
- 程序员_Java基础之<九>-泛型、其他对象
- Java基础<十>_集合(下)
- Java基础<十二>--->集合之map
- 程序员_Java基础之<八>-Map集合、集合工具类
- Java基础<十三>---> 集合-工具类
- Java基础--集合框架<二>
- 黑马程序员 Java基础<七>---> 集合框架
- Java基础--集合框架<一>
- Java基础<九>---> 多线程
- [原]java专业程序代写(qq:928900200),学习笔记之基础入门<jsp>(二十六)
- 黑马程序员 JAVA基础<二> 面向对象之封装 继承 多态
- 黑马程序员 Java基础 ---> 集合(上)
- Java基础知识<2>
- 黑马程序员:Java基础总结----接口 Collection<E>&iterator
- java基础<三>