黑马程序员————Java基础日常笔记---对集合的理解与总结二

------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();

Set<Map.Entry<K,V>>entrySet()

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培训、期待与您交流! -------

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值