------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
黑马程序员————Java基础日常笔记---对集合的理解与总结二
1. Set集合:
一个不包含重复元素的 collection,
首先Set集合的功能和Collection是一致的,
Set集合的特点:
元素是无序的, 元素不可以重复,
所以存入和取出的顺序不一定一致。
如图:
1.1 HashSet集合:
|----Set子类:
|----HashSet:底层数据结构是哈希表
|----TreeSet:底层数据结构是二叉树
集合他存放的哈希地址值的哈希表,存的时候,他存的顺序不是按照你所存的顺序来定义的, 可能按照哈希值的大小来存,
取得时候, 也是按照哈希值来取的。
因此:先看哈希值, 然后看是否是同一个对象,这样来判断集合的唯一性。
他会自动调用集合中元素对象的hashCode方法和equals方法。
如果往HashSet集合中添加自定义对象元素,姓名和年龄相同视为同一个人,
这时就需要重写自定义对象的HashCode方法和Equals方法了,以保证集合元素的唯一性。
代码如下:
/*
|--Set: 元素是无序的(存入和取出的顺序不一定一致),元素不可以重复
|--HashSet:底层数据结构是哈希表
|--TreeSet:
*/
import java.util.*;
class Person
{
private String name;
private int age;
Person(String name,int age){
this.name=name;
this.age=age;
}
public boolean equals(Object obj){//重写equals方法,判断name,age,是否相等
if(!(obj instanceof Person)){//注明:此处的obj是在哈希表中的前面存进来的对象地址
return false;
}
Person p=(Person)obj;
System.out.println(this.name+"......"+p.name);
return this.name.equals(p.name)&&(this.age==p.age);
}
public int hashCode(){//设置哈希地址值,这里写错过, 写成了hasCode, 导致读不出来
System.out.println(this.name+"hasCode");
return this.name.hashCode()+age*17;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
class HashSetDemo
{
public static void main(String[] args)
{
HashSet hs=new HashSet();
//sop(hs.add("java01"));//add方法返回的是boolean类型
hs.add(new Person("a1",11));
hs.add(new Person("a2",12));
hs.add(new Person("a2",12));
hs.add(new Person("a3",13));
hs.add(new Person("a4",14));//运行下面的语句之前先将重复的对象删除,先底层运行hashCode方法,后equals方法
Iterator it=hs.iterator();
while(it.hasNext()){
Person p=(Person)it.next();
sop(p.getName()+"..."+p.getAge());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
Hashset判断和删除的依据:
这样就说明: Hashset判断和删除的,依赖的方法是元素的hashCode和equals方法。
1.2 TreeSet集合:
这个集合虽然和我们存的时候的顺序不同, 但是他在输出的时候,却是有自己的顺序,他会按照字母的顺序输出。
TreeSet:可以对Set集合中的元素进行排序。
为何会按照字母的顺序输出?
原因:在于这个集合中的元素String类,有compareTo方法,因为他实现了Comparable接口, 因此让字符串类具备了比较性。
那么自定义对象在TreeSet集合中又是如何存的呢?
首先TreeSet会根据元素中的默认自然顺序来排序输出, 而自定义对象的类中没有这个功能, 因此,如果直接存储的话,
会出现异常,,学生类无法转换成,因此需要在定义这个自定义类的时候, 需要重写Comparable类中的compareTo(),使这个类具备比较性。
代码如下:
import java.util.*;
class Student implements Comparable
{
private String name;
private int age;
Student(String name,int age){
this.name=name;
this.age=age;
}
public int compareTo(Object obj){
if(!(obj instanceof Student)){
throw new RuntimeException("不是学生对象");
}
Student s=(Student)obj;
System.out.println(this.name+"....compare to....."+s.name);
if(this.age>s.age){
return 1;
}
if(this.age==s.age){
return this.name.compareTo(s.name);
}
return -1;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts=new TreeSet();//往TreeSet集合中存储自定义对象学生,想按学生的年龄进行排序
ts.add(new Student("lisi02",22));
ts.add(new Student("lisi009",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi07",19));
ts.add(new Student("lisi07",30));
ts.add(new Student("lisi01",40));
Iterator it=ts.iterator();
while(it.hasNext()){
Student stu=(Student)it.next();
System.out.println(stu.getName()+"...."+stu.getAge());
}
}
}
说明底层会调用compareTo方法,
TreeSet底层的数据结构是二叉树,那什么是二叉树?
通过compareTo方法实现。
如果想他怎么存进去的怎么取出来的话,
因此:
TreeSet保证元素的唯一性的依据是:compareTo方法中的return 0.
以上是通过实现Comparable方式来实现的,
下面是通过实现Comparator方式排序:
由来:
万一元素真的不具备比较性,这个类是别人定义的,他没有实现Comparable , 那么元素就不具备比较性了,
或者说是有比较性, 但是现在想按照姓名排, 这时排序方式也变了,
通过实现Comparable方式,是让元素本身具备比较性, 而通过通过实现Comparator方式则是让集合具有比较性。
定义比较器(Comparator),将比较器对象作为参数传递给TreeSet集合的构造函数,就可以实现了,
就像集合有了刻度板。
代码如下:
import java.util.*;
class Student implements Comparable
{
private String name;
private int age;
Student(String name,int age){
this.name=name;
this.age=age;
}
public int compareTo(Object obj){
if(!(obj instanceof Student)){
throw new RuntimeException("不是学生对象");
}
Student s=(Student)obj;
System.out.println(this.name+"....compare to....."+s.name);
if(this.age>s.age){
return 1;
}
if(this.age==s.age){
return this.name.compareTo(s.name);
}
return -1;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
class TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts=new TreeSet(new MyCompare());//往TreeSet集合中存储自定义对象学生,想按学生的年龄进行排序
ts.add(new Student("lisi02",22));
ts.add(new Student("lisi009",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi07",19));
ts.add(new Student("lisi07",30));
ts.add(new Student("lisi01",40));
Iterator it=ts.iterator();
while(it.hasNext()){
Student stu=(Student)it.next();
System.out.println(stu.getName()+"...."+stu.getAge());
}
}
}
class MyCompare implements Comparator
{
public int compare(Object o1,Object o2){
Student s1=(Student)o1;
Student s2=(Student)o2;
int num=s1.getName().compareTo(s2.getName());//直接调用字符串的compareTo方法,
if(num==0){
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
}
return num;
}
}
当两个排序的方式都存在的时候, 以比较器为主
2,Map集合
在使用的时候, 需要往里面传两个元素,键,值, 代表他们的映射关系,
他们是一对一对往里存的,而且要保证键的唯一性。
Collection是单列集合,
Map是双列集合,
Map集合的方法:2.1 添加:
put(K key,V value)
putAll(Map<? extendsK,? extends V> m
);
2.2 删除
clear();
remove(Object key);
2.3 判断
containsValue(Object value);
containsKey(Object key);
isEmpty();
2.4 获取
get(Object key)
size();
values();
Set<K> keySet();
Map子集合
|----HashTable: 底层是哈希表数据结构,但是不可以存入null键和null值,线程同步,效率低
|----HashMap:底层是哈希表数据结构,可以存入null键和null值,线程不同步,效率高
|----TreeMap:底层是二叉树数据结构,线程不同步,可以用于给Map集合中的键进行排序。
这里也可以用get方法来判断某一个键值是否存在,并获取这个键的值。
这里如何来获取所有的值呢?
map集合中有两种取出方式:
1,keySet:将map中的所有的键存入到Set集合,因为set集合具备迭代器,
所有可以迭代方式出去所有的键,在根据get方法,获取每个键对应的值。
代码如下:
import java.util.*;
class MapDemo2
{
public static void main(String[] args)
{
Map<String,String> map=new HashMap<String,String>();
map.put("02","zhangsan02");
map.put("03","zhangsan03");
map.put("04","zhangsan04");
map.put("05","zhangsan05");
map.put("06","zhangsan06");
//先获取map集合的所有的键的Set集合,keySet();
Set<String> keyset=map.keySet();
//有了set集合,就可以获取其迭代器
Iterator<String> it=keyset.iterator();
while(it.hasNext()){
String key=it.next();
String value=map.get(key);
System.out.println(key+"对应的值"+value);
}
图解:
2,entrySet:将map集合中的映射关系存入到set集合中,而这个关系的数据类型就是:Map.Entry.
其中的方法:
代码如下:
Map<String,String> map=new HashMap<String,String>();
map.put("02","zhangsan02");
map.put("03","zhangsan03");
map.put("04","zhangsan04");
map.put("05","zhangsan05");
map.put("06","zhangsan06");
//将Map集合中的映射关系取出,存入到Set集合中
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();
System.out.println(key+"..."+value);
将学生存入集合中,并明确姓名和年龄相同的视为同一个学生,保证学生的唯一性。
存入的对应学生有他的地址,
代码如下:
import java.util.*;
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 int getAge(){
return age;
}
public String toString(){
return name+"名字对应的年龄:"+age;
}
//判断唯一性:一会存到hashmap 中, 而hashmap 是一个哈希表,就需要hashcode和equals,
public int hashCode(){
return name.hashCode()+age*17;
}
public boolean equals(Object obj){
if(!(obj instanceof Student)){
return false;
}
Student s=(Student)obj;
return this.name.equals(s.name)&&this.age==s.age;
}
public int compareTo(Student s){
int num=new Integer(this.age).compareTo(new Integer(s.age));
if(num==0){
return this.name.compareTo(s.name);
}
return num;
}
}
class MapTest
{
public static void main(String[] args)
{
/*
HashMap<Student,String> hm=new HashMap<Student,String>();
hm.put(new Student("lisi01",11),"beijing");
hm.put(new Student("lisi02",12),"shanghai");
hm.put(new Student("lisi03",13),"tianjin");
hm.put(new Student("lisi04",14),"wuhan");
hm.put(new Student("lisi05",15),"nanchang");
*/
TreeMap<Student,String> tm=new TreeMap<Student,String>(new StuNameComparator());
tm.put(new Student("lisi03",11),"beijing");
tm.put(new Student("lisi02",12),"shanghai");
tm.put(new Student("lisi01",13),"tianjin");
tm.put(new Student("lisi02",14),"wuhan");
tm.put(new Student("lisi05",15),"nanchang");
/*
//通过keySet获取
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);
}
*/
//通过entrySet获取
Set<Map.Entry<Student,String>> entryset=tm.entrySet();
Iterator<Map.Entry<Student,String>> ite=entryset.iterator();
while(ite.hasNext()){
Map.Entry<Student,String> me=ite.next();
Student stu=me.getKey();
String addre=me.getValue();
System.out.println(stu+"和这个学生的地址是:"+addre);
}
}
}
class StuNameComparator implements Comparator<Student>
{
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;
}
}
综合练习二:
"abcabcdea"获取该字符串中的字母出现的次数
希望打印结果:a(1)c(2)...
通过结果发现,每一个字母都有对应的次数,
说明字母和次数都有映射关系,
注意了,当发现有映射关系是, 可以选择map集合,
因为map集合中存放的是映射关系,
什么时候使用map集合?
当数据之间存在着映射关系时,就要先想map集合,
思路:
1, 将字符串转换成字符数组,因为要对每一个字母进行操作,
2, 定义一个map集合,因为打印的结果的字母有顺序,所以使用treemap集合,
3, 遍历字符数组
将每一个字母作为键去查map集合
如果返回null,将该字母和1存入到map集合中,
如果返回的不是null,说明该字母在map集合中已经存在并有对应的次数,
那么久获取该次数并进行自增,然后将该字母和自增后的次数存入到map集合中,覆盖调用
原理键所对应的值。
4, 将map集合中的数据变成指定的字符串形式返回
import java.util.*;
class MapTest2
{
public static void main(String[] args)
{
System.out.println(charCount("abcabcdea"));
}
public static String charCount(String str){
char[] chs=str.toCharArray();//将字符串变成字符数组
//因为打印的结果的字母有顺序,所以使用treemap集合,
TreeMap<Character,Integer> tm=new TreeMap<Character,Integer>();
/*
for(int i=0;i<chs.length;i++){
Integer value=tm.get(chs[i]);
if(value==null){
tm.put(chs[i],1);
}
else{
value=value+1;
tm.put(chs[i],value);
}
}
*/
int count=0;
for(int i=0;i<chs.length;i++){
if(!(chs[i]>'a'&&chs[i]<'z'||chs[i]>'A'&&chs[i]<'Z')){
continue;
}
Integer value=tm.get(chs[i]);//这里有值了, 就把返回值给了value;
if(value!=null){
count=value;
}
count++;
tm.put(chs[i],count);
count=0;
}
//System.out.println(tm);
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();
}
}
Map扩展:
在映射关系中, 不仅有一对一的映射,还有一对多的映射关系,
比如:一个学校有多个班级,一个班上有多个学生对象,
代码实现如下:
import java.util.*;
class Student
{
private String id;
private String name;
Student(String id,String name){
this.id=id;
this.name=name;
}
public String toString(){
return id+".."+name;
}
}
class MapDemo4
{
public static void main(String[] args)
{
HashMap<String,List<Student>> czbk=new HashMap<String,List<Student>>();
List<Student> yure=new ArrayList<Student>();
List<Student> jiuye=new ArrayList<Student>();
czbk.put("yureban",yure);
czbk.put("jiuyeban",jiuye);
yure.add(new Student("01","zhangsan"));
yure.add(new Student("02","lisi"));
jiuye.add(new Student("01","zhaoliu"));
jiuye.add(new Student("02","lisi01"));//这样就是一对多的关系
Set<Map.Entry<String,List<Student>>> entryset=czbk.entrySet();
Iterator<Map.Entry<String,List<Student>>> it=entryset.iterator();
while(it.hasNext()){
Map.Entry<String,List<Student>> me=it.next();
String bj=me.getKey();
List<Student> stu=me.getValue();
System.out.println(bj);
getStudentInfo(stu);
}
}
public static void getStudentInfo(List<Student> list){
Iterator<Student> it=list.iterator();
while(it.hasNext()){
Student stu=it.next();
System.out.println(stu);
}
}
}
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------