黑马程序员---集合类

-----------android培训java培训、java学习型技术博客、期待与您交流!---------

      

集合类

      

      首先我们来看一个集合的关系图



        

            

            (因为是网上直接有的,我就不自己画了,浪费时间,嘿嘿)


      为什么出现集合类?


            面向对象语言对实物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,


            集合就是存储对象最常用的一种方式。(对象多了用集合存,数据多了用对象存)

        

      数组和集合类同是容器,有何不同?


            数组虽然也可以存储对象,但长度是固定的


            集合长度是可变的,数组中可以存储基本数据类型,集合只能存储对象。

 

      集合类的特点


            集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

 

      为什么会出现这么多的容器呢?


            因为每一个容器对数据的存储方式都有不同,这个存储方式称之为:数据结构。     


            每一个容器因为数据结构不同,所以进行了单独的划分。因为他们自身的特点不同

 

      在最先展示的java中集合类的关系图中,可以看到第一行的 Iterator,Collection,Map三个接口。其中Iterator是迭代器,用来遍历集合的,先不介绍。


            最先开始了解Collection接口,它又有两个子接口List,Set。我们先来学习父类,因为父类是通过不断抽取得来的,有子类的共性,


            先学会了共性方法,再去学习子类的特有方法。


Collection


            所属关系


                  Collection


                        |----List     //元素是有序的,可以重复,因为List体系内有索引


                        |----Set     //元素是无序的,不可以重复

 

            对象中存储的都是对象的引用(地址)。

 

            Collection接口的常见操作


                  1.   添加元素


                         boolean  add(Object  obj)        //add方法的参数类型是Object,以便于接收任意类型对象。


                  2.   获取个数,集合长度


                        int  size()           //获取集合内元素的个数


                  3.   删除元素


                        boolean  remove(Object  obj)      //从集合中移除指定元素的单个实例,如果删除成功返回true


                        void  clear()      //移除这个集合中所有的元素


                  4.   判断元素


                        boolean  contains(Object  obj);            //如果此集合中包含obj元素,返回true


                        boolean  isEmpty();             //判断这个集合是否为空


                  5.   交集


                        boolean removeAll(Collection<?> c);          //<>一会儿会讲,这个集合保留和c集合不同的元素


                        boolean reainAll(Collection<?> c);             //这个集合保留和c集合相同的元素

        

迭代


      刚才我们提过一句的迭代器Iterator,迭代是取出集合中元素的一种方式。


            (对于取出,不只一个动作的话,就将取出这个动作封装成为一个对象,对于取出不足以用一个动作来描述,


                需要多个功能来体现,就把多个功能封装进一个对象中,因为数据结构不同,每个取出对象取出的实现方式也不一样,那么取出就需要被描述,


                通过类来描述,类就定义在了集合内部,因为元素在集合中,操作的是元素,直接操作元素最方便的就是内部类,因为在集合内部才做最方便,


                内部类就完成取出动作,每个容器都有内部类,内部类都有一个共性,会判断,判断是否有元素)

 

      把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素,那么取出方式就被定义成了内部类,


            而每个容器的数据结构不同,所以取出的动作细节也不一样,但是都有共性内容,判断和取出,


            那么可以将这些共性抽取一个规则(这些内部类中抽取一个规则),这个规则就是Iterator

 

      如何获取集合的取出对象呢?


            通过一个对外提供的方法:iterator();

 

      迭代的常见操作


            boolean hasNext()            //如果还有下一个元素,返回true,可以作为循环条件


            E next()                               //返回迭代的下一个元素


            void remove()                    //移除迭代器返回的最后一个元素

        

            注:在迭代时循环中next调用一次,就要hasNext判断一次。

 

      迭代器的使用方法示例

/*
这里我用到的东西可能前面没有讲过,因为我是学完了所有课程回来复习
写的博客,所以为了养成好的习惯,我还是使用完整的代码。

其实这些代码都是我用EditPlus写的,虽然我已经回用eclipes了,但是觉得这样写比较好
不会有自动联想,也不会有错误提示,可以增强手写代码的能力,建议初学者也是,后期使用eclipse比较好
我现在博客写到这人,敲代码真的比以前顺畅多了,亲测有效!!哈哈

话不多说,来看Iterator使用的实例
*/
import java.util.*;

class IteratorDmeo
{
	public static void main(String[] args)
	{
		//先创建一个集合
		Collection<String> c = new ArrayList<String>();
		//往集合中添加元素
		c.add("潘机智1号");
		c.add("潘机智2号");
		c.add("潘机智3号");
		c.add("潘机智4号");
		c.add("潘机智5号");

		//输出集合
		System.out.println(c);

		//方法1 方法2 都是通过迭代器获取集合中的元素,不同的是迭代器获取的位置
		//方法1 在循环外单独获取
		//方法2 在循环体上获取

		//方法1
		//获取一个迭代去
		System.out.println("方法1");
		//获取一个迭代器对象
		Iterator<String> it1 = c.iterator();
		//建立一个循环,hasNext()语句作为循环条件
		while(it1.hasNext())
		{
			//输出集合
			System.out.println(it1.next());
		}

		//方法2
		System.out.println("方法2");
		//在for循环的初始化表达位置,获得迭代器对象
		for(Iterator<String> it2 = c.iterator() ; it2.hasNext();)
		{
			System.out.println(it2.next());
		}
	}
}


            运行结果



      

List


      组成关系


            List                  //元素是有序的,元素可以重复,因为该集合体系有索引。


                  |----ArrayList             //底层的数据结构是数组结构。


                  |----LinkedList           //底层的数据结构是表链数据结构。


                  |----Vector                  //底层的数据结构是数组数据结构。

 

      List的特有方法


            凡是可以操作角标的方法都是该体系特有的方法


                  1.   增


                        void  add(int  index , E  element)          在列表指定位置插入指定元素


                        boolean  addAll(int  index , Collection<? extends E>  c)            将Collection中的元素都插入到列表中的指定位置


                  2.   删


                        E  remove(int  index)             移除列表中指定位置的元素


                  3.   改


                        E  set(int  index , E  element)            用指定元素替换列表中指定位置的元素


                  4.   查(获取)


                        E  get(int  index)            返回列表中指定位置的元素


                        List<E>  subList(int  fromIndex , int  toIndex)            返回列表中从指定位置开始到指定位置结束的元素的集合(包头不包尾)


                        ListIterator<E>   listIterator()            返回此列表元素的列表迭代器


                        int  indexOf(Object  obj)            获取obj元素第一次出现的位置,没有则返回-1

 

      List集合特有的迭代器


            ListIterator


                  它是Iterator的子接口,在迭代时不可以通过集合对象的方法操作集合中的元素,因为会发生并发修改异常。


                        所以在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作,


                        如果想要其他的操作如:添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator()方法获取。


                        ListIterator出现以后可以对集合进行在遍历的过程中的增删改查。

                           

                  ListIterator的特有方法


                        1.   void  add(E e)            将指定元素插入列表


                        2.   void  set(E  e)            用指定元素替换next()或者previous()返回的最后一个元素


                        3.   boolean  hasPrevious()            逆向遍历列表,列表迭代器有多个元素,返回true


                        4.   E  previous()            返回列表中的前一个元素


      面试题:


            List集合具体对象的特点


                  ArrayList:查询速度快,但是增删稍慢,线程不同步。


                  LinkedList:增删速度很快,查询稍慢。


                  Voector:线程同步,被ArrayList替代了。


            ArrayList和Vectot的区别


                  数组是固定长度,但集合是可变长度,ArrayList和Vectot默认的长度都为10,当元素个数超过10个,


                  还需要往里添加元素时就会new一个新的集合。ArrayList为50%延长,也就是变为了15。Vctor为100%延长,也就是变为了20.


                  把原来数组中的元素copy到新集合中,再把新加进来的元素添加进去,所以相比之下ArrayList比较节省空间。

      

       Vertor


             枚举(Enumeration)是Vector特有的取出方式。


                    发现枚举和迭代器很像。其实枚举和迭代器是一样的,因为枚举的名称以及方法的名称都过长,所以被迭代器取代了。

 

                    特有方法


                          1.   void  addElement(E  obj)             添加元素,相当于add(obj)


                          2.   Enumeration<E>  elements()      返回此向量的组件的枚举,获取美剧对象的方法


                          3.   boolean  hasMoreElements()             相当于Iterator的hasNext()方法


                          4.   E  nextElement()              相当于Iterator的newt()方法

 

                    用枚举取出Vetor集合中元素示例


                          Collection<E> c = new Vertor<E>();


                          for(Enumeration<E> e =c.elements() ; e.hasMorElements() ; )  {


                                 System.out.println(e.nextElement());


                          }

                  

       LinkedList


             底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。

 

             特有方法


                    1.   void  addFirst(E  e)             将指定元素插入该列表的开头


                    2.   void  addLast(E  e)             将指定元素添加到该列表的结尾


                    3.   E  getFirst()             返回此列表的第一个元素


                    4.   E  getLast()             返回此列表的最后一个元素


                    3,4两个方法,获取元素,但不删除元素,如果集合中没有元素会出现NoSuchElmentException


                    5.   E   removeFirst()             返回并移除此列表的第一个元素


                    6.   E   removeLast()             返回并移除此列表的最后一个元素。


                    5,6两个方法,获取元素,元素会被删除,如果集合中没有元素会出现NoSuchElmentException

 

                    在JDK1.6版本之后出现了替代方法


                          为了使博客不那么拖拉,我就按照上面的方法顺序写,用法是一样的,有不一样的会写明


                                 1.      boolean  offerFirst()             将指定元素插入该列表的开头


                                 2.      boolean  offerLast()             将指定元素添加到该列表的结尾


                                 3.      E   peeckFirst()             返回此列表的第一个元素,列表为空返回null


                                 4.      E   peekLast()             返回此列表的最后一个元素,列表为空返回null


                                 5.      E   poolFirst()             返回并移除此列表的第一个元素,列表为空返回null

     

                                 6.      E   poolLast()             返回并移除此列表的最后一个元素,列表为空返回null

 

     ArrayList练习

/*
ArrayList练习

将自定义对象作为元素存到ArrayList集合中,并去除重复元素。

比如定义一个Person类,同姓名同年龄视为一个人,是相同元素
*/

import java.util.*;

//先创建person类
class Person
{
	//Person类中有两个属性,name age
	private String name;
	private int age;
	//构造函数,传入姓名年龄,用于初始化对象。
	Person(String name , int age)
	{
		this.name = name;
		this.age = age;
	}

	//得到名字方法
	public String getName()
	{
		return name;
	}
	//得到年龄方法
	public int getAge()
	{
		return age;
	}

	//复写equals方法,定义姓名和年龄相同的是同一个对象。
	public boolean equals(Object obj)
	{
		//先来判断用户传入的obj是否是Person或者Person的子类
		if(!(obj instanceof Person))
			//如果不是,返回false
			return false;

		//如果传入的obj是Person或者它的子类运行以下代码
		//将obj转成Person类
		Person p = (Person)obj;

		//比较调用equals方法的对象和p对象的姓名和年龄是否相同,并返回结果
		//因为name是String类型的,所以可以直接调用equals,String类复写了
		//equals方法,使它只比较字符串的内容是否相同,年龄用==比较即可
		return this.name.equals(p.name) && this.age == p.age;
	}
}

class ArrayListTest
{
	public static void main(String[] args)
	{
		//创建一个ArrayList集合
		ArrayList<Person> cal = new ArrayList<Person>();

		//往集合中添加元素
		cal.add(new Person("张三",45));
		cal.add(new Person("李四",31));
		cal.add(new Person("王五",14));
		//跟第一个同岁的
		cal.add(new Person("赵六",45));
		//跟第一个完全相同的
		cal.add(new Person("张三",45));
		//根第一个同名的
		cal.add(new Person("张三",19));

		//调用获取唯一元素的方法
		cal = singleElement(cal);

		//迭代集合并打印集合中的元素,来看一看是否把重复的元素加进去了
		for(Iterator<Person> it = cal.iterator() ; it.hasNext() ;)
		{
			Person p = it.next();
			//通过Person类的getName 和getAge方法获取姓名年龄并打印结果
			System.out.println(p.getName()+"........"+p.getAge());
		}
	}
	
	//获取唯一元素的方法
	public static ArrayList<Person> singleElement(ArrayList<Person> cal)  
    {  
		//新定义一个集合
        ArrayList<Person> newCal = new ArrayList<Person>();  
  
		//迭代参数传入的集合
        for(Iterator<Person> it = cal.iterator(); it.hasNext();)  
        {  
			//用Person类型变量接收 读取到的集合中的元素
            Person p = it.next();  
			//判断一个元素是否已经在newCal集合中,就是在比较集合中有没有和newCal一样的。
            if(!newCal.contains(p))  
            {  
				//如果不存在,再往里添加
                newCal.add(p);  
            }  
        }  
		//返回新数组
        return newCal;  
    }  
}


               运行结果



 

     LinkList练习

/*
LinkList练习

因为毕老师的例子比较经典,就用老师的例子。
但是用我自己的想法写出来

使用LinkedList模拟一个堆栈或者队列数据结构。

堆栈:先进后出  如同一个杯子。先倒进去的水最后才能喝到
队列:先进先出 First in First out  FIFO 如同一个水管。先进去的水会先出来
*/

import java.util.*;

class LinkedListTest
{
	public static void main(String[] args)
	{
		//先创建一个LinkedList集合
		LinkedList<String> l = new LinkedList<String>();

		//往里面按顺序的添加元素
		l.add("水一号---1");
		l.add("水二号---2");
		l.add("水三号---3");
		l.add("水四号---4");

		//调用模拟堆栈方法
		duiZhan(l);

		//模拟队列方法
		//duiLie(l);
	}

	//模拟堆栈方法,先进后出,先存进去的元素最后输出
	public static void duiZhan(LinkedList<String> l)
	{
		//创建一个循环,集合里是否还有元素是循环条件
		//集合里没有元素了循环停止
		while(!l.isEmpty())
		{
			//使用LinkedList的特有方法,removeLast()
			//获取并且删除集合里的最后一个元素。然后打印该元素
			System.out.println(l.removeLast());
		}
	}

	//模拟队列方法,先进先出,先存进去的元素最先输出
	public static void duiLie(LinkedList<String> l)
	{
		//创建一个循环,集合里是否还有元素是循环条件
		//集合里没有元素了循环停止
		while(!l.isEmpty())
		{
			//使用LinkedList的特有方法,removeFirst()
			//获取并且删除集合里的第一个一个元素。然后打印该元素
			System.out.println(l.removeFirst());
		}
	}
}


               模仿堆栈的运行结果



 


Set

      

      Set:元素是无序的(存入和取出的顺序不一定一致)元素不可重复


            |----HashSet:底层数据结构是哈希表,线程是非同步的


            |----TreeSet:底层数据结构是二叉树,可以对Set集合中的元素进行排序

 

            Set集合的功能和Collection是一致的。

 

      HashSet


            HashSet:线程不安全,存取速度快。

 

            理解:HashSet内的元素排序是地址值,当地址的哈希值一致时,判断是不是两个不同的对象。

 

            HashSet是如何保证元素唯一性的呢?


                  是通过元素的两个方法,hashCode()和equals()方法来完成的


                        如果元素的HashCode值相等,才会判断equals是否为true,如果元素的HashCode值不相同,不会调用equals。


                        以上就是HashSet保证元素唯一性的依据。


                  而且当我们在自定义对象需要往集合里存时,一般都重写hashCode()equals()方法

 

            注意:对于判断元素是否存在,以及删除等操作,依赖的是元素的hashCode()和equals()方法,


                        ArrayList依赖equals()                                  HashSet依赖hashCode()和equals()

                                    

            HashSet练习

/*
HashSet练习

往HashSet集合中存入自定对象
姓名和年龄相同为同一个人,重复元素。

不能存进重复元素

*/
import java.util.*;

//先创建一个Person类
class Person
{
	//人有姓名年龄属性
	private String name;
	private int age;
	Person(String name , int age)
	{
		this.name = name;
		this.age = age;
	}

	//复写hashCode方法,使相同元素的HashCode值相同
	public int hashCode()
	{
		//返回自定义的HashCode值,其中字符串调用的hashCode()是String类的方法
		//返回这个字符串的hashCode值
		return name.hashCode()+age*18;
	}
	//复写equals方法
	public boolean equals(Object obj)
	{
		//判断传入的obj是否是Person或者它的子类实例
		if(!(obj instanceof Person))
			//如果不是返回false
			return false;
		//把obj转成Person类的实例
		Person p = (Person)obj;
		//判断调用equals的内容是否和obj中的内容个相同,并返回结果
		return this.name.equals(p.name)&& this.age == p.age;
	}

	//获取姓名的方法
	public String getName()
	{
		return name;
	}
	//获取年龄的方法
	public int getAge()
	{
		return age;
	}
}
class HashSetTest
{
	public static void main(String[] args) 
	{
		//创建一个HashSet集合
		HashSet<Person> hs = new HashSet<Person>();

		//往HashSet集合中存入元素
		hs.add(new Person("潘机智1号---1",21));
		hs.add(new Person("潘机智2号---2",18));
		hs.add(new Person("潘机智3号---3",34));
		//和第一个一样
		hs.add(new Person("潘机智1号---1",21));
		//和第一个名字不一样
		hs.add(new Person("潘机智7号---7",21));
		//和第一个年龄不一样
		hs.add(new Person("潘机智1号---1",99));

		//迭代集合
		for(Iterator<Person> it=hs.iterator() ; it.hasNext();)
		{
			//将集合中的元素用Person型的变量接收
			Person p = it.next();
			//通过Person的方法获得name和age并输出
			System.out.println(p.getName()+"...."+p.getAge());
		}
	}
}


                  运行结果



 

      

      TreeSet


            底层的数据结构为二叉树结构


            特点:


                  可对Set集合中的元素进行排序,TreeSet类实现了Comparable接口,该接口强制让增加到集合中的对象进行了比较,


                  需要复写compareTo方法,才能让对象按指定需求(如人的年龄大小比较等)进行排序,并加入集合。

 

                  java中的很多类都具备比较性,其实就是实现了Comparable接口。

 

            注意:排序时,当主要条件相同时,按次要条件排序。如姓名一样,就按年龄排序


            保证数据的唯一性的依据


                  通过compareTo方法的返回值,负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。

 

            TresSet排序的两种方式


                  1.   自然排序


                        让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也被称为元素的自然顺序,或者叫做默认顺序。

 

                        TreeSet自然排序示例


/*
TreeSet的第一种排序方式

这里我们还是使用Person作为自定义对象

*/

//Person类实现Comparable接口,强制让人具备比较性
import java.util.*;
class Person implements Comparable
{
	private String name;
	private int age;
	Person(String name , int age)
	{
		this.name = name;
		this.age = age;
	}

	//复写compareTo方法
	public int compareTo(Object obj)
	{
		//判断obj是否是Person或者它子类的实例
		if(!(obj instanceof Person))
			//如果不是抛出RuntimeException
			throw new RuntimeException("不是人对象");
		//将obj转成Person型
		Person p = (Person)obj;
		//判断年龄是否相等
		if(this.age == p.age)
			//如果相等再比较姓名。其中用到的compareTo方法是String重新复写的
			//仅仅用于,按字典顺序比较两个字符串
			return this.name.compareTo(p.name);
		//如果年龄不相等的话直接返回两个对象的年龄差
		return this.age - p.age;
	}

	//获取姓名的方法
	public String getName()
	{
		return name;
	}
	//获取年龄的方法
	public int getAge()
	{
		return age;
	}
}

class TreeSetTest1 
{
	public static void main(String[] args) 
	{
		//创建一个TreeSet集合
		TreeSet<Person> ts = new TreeSet<Person>();

		//往集合中添加元素
		ts.add(new Person("pt01",30));
		ts.add(new Person("pt002",19));
		ts.add(new Person("pt07",30));
		ts.add(new Person("pt077",45));
		ts.add(new Person("pt008",30));
		ts.add(new Person("pt009",35));

		//迭代集合,输出元素
		for(Iterator<Person> it=ts.iterator() ; it.hasNext();)
		{
			Person p = it.next();
			System.out.println(p.getName()+"...."+p.getAge());
		}

	}
}

                              

                     运行结果



      

                  2.   比较器


                        当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。


                              在集合初始化时,就有了比较方式。定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

 

                        比较器构造方式:定义一个类,实现Comparator接口,覆盖compare方法。

 

                        当两种排序都存在时,以比较器为主。

 

                        TreeSet比较器排序示例

/*
TreeSet的第二种排序方式

依然用Person作为自定义对象

类自带的排序方式不是我们想要的。
我们想要按name来排序

*/
import java.util.*;

//创建Person类实现Comparable接口
class Person implements Comparable 
{
	private String name;
	private int age;
	Person(String name , int age)
	{
		this.name = name;
		this.age = age;
	}

	//复写compareTo方法,以便TreeSet集合调用
	public int compareTo(Object obj)
	{
		//跟上一个程序一样
		if(!(obj instanceof Person))
			throw new RuntimeException("不是Person类");
		Person p = (Person)obj;
		if(this.age == p.age)
			return this.name.compareTo(p.name);
		return this.age - p.age;
	}
	//获取姓名方法
	public String getName()
	{
		return name;
	}
	//获取年龄方法
	public int getAge()
	{
		return age;
	}
}

//定义一个比较器,比较名字长度排序
class myCompare implements Comparator<Person>
{
	//复写compare方法
	public int compare(Person p1 , Person p2)
	{
		//比较姓名的顺序,并返回结果
		int num = p1.getName().compareTo(p2.getName());
		//判断num是否等于0,如果是表示姓名一样
		if(num==0)
		{
			//再比较年龄,返回结果
			return new Integer(p1.getAge()).compareTo(new Integer(p2.getAge()));
		}
		//返回num
		return num;
	}
}

class  TreeSetTest2
{
	public static void main(String[] args) 
	{
		//建立一个TreeSet集合,将比较器作为参数传递给TreeSet的构造函数
		TreeSet<Person> ts = new TreeSet<Person>(new myCompare());

		//往集合中添加元素
		ts.add(new Person("pt01",30));
		ts.add(new Person("pta002",19));
		ts.add(new Person("pt07",30));
		ts.add(new Person("pt077",45));
		ts.add(new Person("pt708",30));
		ts.add(new Person("pt009",35));

		//迭代并打印集合
		for(Iterator<Person> it = ts.iterator() ; it.hasNext();)
		{
			Person p = it.next();
			System.out.println(p.getName()+"..."+p.getAge());
		}
	}
}


                              运行结果



                           

      

      Map

            

            该集合存储键值对,是双列集合。Map<k , v>  键 key  值 value

 

            特点


                  该集合存储键值对,一对一对往里存。


                  要保证键的唯一性


                  键和值之间的关系是映射关系

 

            Map


                  |----Hashtable:底层是哈希表数据结构,不可以存入null键,null值的情况,该集合是线程同步的。JDK1.0,效率低。


                  |----HashMap:底层哈希表数据结构,允许使用null键和null值,该集合不同步,JDL1.2,效率高


                  |----TreeMap:底层是二叉树数据结构,可以用于给Map集合中的键进行排序

 

            Map和Set很像,其实Set底层就是使用了Map集合。

 

            Map集合常见方法

                  

                  1.   添加


                        V  put( K key , V value)            将指定的值与此映射中的指定键关联。


                        当存储了相同的键时,新的值会替换老的值,put方法还会把这个键原来的值返回来。


                        当在存第一个键时,没有对应的值,返回的是null。put方法会返回这个键原来的值。


                        个人理解:就像商场里的自助照相机,就是一个键,我进去了里面,没有人就返回null,我朋友要进来,把我挤出来了,


                                             返回的就是我。这个键现在对应的就是我朋友,所以添加元素时,若果出现相同的键,


                                             那么后添加的值会覆盖键对应的原有的值,并且put()方法会返回被覆盖(挤掉)的值,


                                             这也就是为什么put()方法,返回值是V(value参数的类型)的原因。


                        void  putAll(Map<? extends K , ? extends V>  m)            从指定映射中将所有的映射关系复制到此映射中


                  2.   删除


                        void  clear()            从此映射中移除所有映射关系


                        V  remove(Object  key)            移除指定键对应的值,并返回这个值,如果此键没有映射关系,返回null


                  3.   判断


                        boolean  containsKey(Object  key)            如果此映射包含指定键的映射关系,则返回true


                        boolean  containsValue(Object  value)            如果此映射将一个或多个键映射到指定值,则返回true


                        boolean  isEmpty()             如果此映射未包含键-值映射关系,则返回 true


                  4.   获取


                        V  get(Object  key)            返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回null


                              可以通过get方法的返回值来判断一个键是否存在,通过是否返回null来判断。


                        int  size()            返回此映射中的键-值映射关系数,也就是集合大小


                        Collection<V>  values            返回此映射中包含的值的Collection视图,也就是说把Map集合中的值都取出,存入一个Collection集合中。


                        Set<Map.Entry<K,V>> entrySet()            将此Map集合的映射关系返回到一个Set集合中


                        Set<K> keySet()            将此映射中所有的键返回到一个Set集合中


                        最后两个方法是用于取出Map集合中元素的,等一下会仔细讲解。

 

            Map集合的两种取出方式


                  1.   Set<K>  keyset():将Map中所有的键存入到Set集合中


                        因为Set具备迭代器,所以Set<K> keySer()方法可以通过迭代方式取出所有的键,再根据get方法获取每一个键对应的值。

 

                        方法一示例

/*
Map集合取出元素方式一

在这里我们主要演示取出元素,所以就不定义自定义对象了
*/
import java.util.*;
class  MapExtractionTest1
{
	public static void main(String[] args) 
	{
		//先创建一个Map集合键是String类型的,值是int型的
		Map<String,Integer> map = new HashMap<String,Integer>();

		//往集合中添加元素
		map.put("pt001",1);
		map.put("pt003",3);
		map.put("pt004",4);
		map.put("pt002",2);

		//先使用keySet()方法将Map集合中所有的键取出,存入一个Set集合中
		Set<String> s = map.keySet();

		//通过迭代器迭代Set集合
		for(Iterator<String> it = s.iterator() ; it.hasNext();)
		{
			//用一个String变量接收key
			String k = it.next();
			//通过get方法获取键对应的值并用int类型变量接收
			int v = map.get(k);
			//打印key和value的值
			System.out.println("ket:"+k+".....value"+v);	
		}
	}
}


                              运行结果



 

                  2.   Set<Map.Entry<K,Y>>  entrySet():将Map集合中的映射关系存入到了Set集合中,而这个关系的数据类型就是Map.Entry。


                        理解:在Map中键值是映射关系,在Set中键值的关系的数据类型就是Map.Entry。键值合起来就是一个Map.Entry的实例对象。


                        那么关系对象Map.Entry获取到后,就可以通过Map.Entry中的getKey和getValue方法获取关系中的键和值。

 

                        Map.Entry到底是什么?


                              其实Entry是一个接口,它是Map接口中的一个内部接口


                              理解:因为有了Map类才会有Entry,而且Entry是描述Map内部键值关系的,所以被封装成了内部接口。

 

                        方法二示例

/*
Map集合取出元素方式二

用的还是取出方法一的创建Map集合和添加元素的代码。只是取出方式不一样
*/
import java.util.*;
class  MapExtractionTest2
{
	public static void main(String[] args) 
	{
		//先创建一个Map集合键是String类型的,值是int型的
		Map<String,Integer> map = new HashMap<String,Integer>();

		//往集合中添加元素
		map.put("pt001",1);
		map.put("pt003",3);
		map.put("pt004",4);
		map.put("pt002",2);

		//使用entrySet方法取出Map集合中的映射关系,存入Set集合中
		Set<Map.Entry<String,Integer>> entrySet = map.entrySet();

		//通过iterator()方法得到迭代器的实例对象
		Iterator<Map.Entry<String,Integer>> it = entrySet.iterator();
		//使用迭代器遍历entrySet集合
		while(it.hasNext())
		{
			//用Map.Entry接收entrySet集合中的元素
			Map.Entry<String,Integer> me = it.next();
			//使用getKey 和 getValue方法取出键和值
			String key = me.getKey();
			int value = me.getValue();

			//输出键和值
			System.out.println("ket:"+key+"=====value"+value);	
		}
	}
}


                              运行结果



 

      

            什么时候使用Map集合呢?


                  当发现有映射关系时,可以选择Map集合,因为Map集合中存放的就是映射关系。

 

            下面来看几个Map集合的练习


                  练习一

/*
Map集合练习一

每一款手机都有对应的生产国籍
比如,苹果美国生产,三星韩国生产,小米中国生产,诺基亚芬兰生产

手机Phone 产地国 String Country

手机属性:品牌,型号,如果品牌和型号相同视为同一个手机。

手机和产地国有了映射关系,所以可以使用Map集合

步骤
1.描述手机
2.定义Map集合,将手机作为键,生产国籍作为值存入集合中
3.取得集合中的元素

*/
import java.util.*;

//先来描述手机,实现Comparable接口使类具备比较性
class Phone implements Comparable<Phone>
{
	//品牌属性
	private String brand;
	//型号属性
	private String model;
	//初始化手机
	Phone(String brand , String model)
	{
		this.brand = brand;
		this.model = model;
	}

	//获取品牌方法
	public String getBrand()
	{
		return brand;
	}
	//获取型号方法
	public String getModel()
	{
		return model;
	}
	//输出方法
	public String toString()
	{
		return "品牌:"+brand+",型号:"+model;
	}

	//因为我们要使用HashMap所以要复写hashCode和equals方法
	public int hashCode()
	{
		//使相同品牌和型号的手机HashCode值相同
		return brand.hashCode()+model.hashCode()+4*18;
	}
	//复写equals方法
	public boolean equals(Object obj)
	{
		//判断obj是否是Phone或其子类的实例
		if(!(obj instanceof Phone))
			//如果不是,抛出RuntimeException使程序停止
			throw new RuntimeException("对象类型不匹配");
		//如果是运行以下代码
		//将obj转成Phone类型
		Phone p = (Phone)obj;
		//判断品牌和型号是否相同,并返回结果
		return this.brand.equals(p.brand) && this.model.equals(p.model);
	}

	//复写compareTo方法。虽然我的例子中是中文 按自然顺序排序也不知道谁会排在前面
	//例子是为了娱乐,但内容必须要有
	public int compareTo(Phone p)
	{
		//使用String的compareTo方法比较品牌的自然顺序,返回值用int类型变量记录
		int num = this.getBrand().compareTo(p.getBrand());
		//如果num==0
		if(num==0)
			//那么再比较型号的自然顺序
			return this.getModel().compareTo(p.getModel());
		//如果num!=0,返回num
		return num;
	}
}

class  MapTest1
{
	public static void main(String[] args) 
	{
		//创建一个Map集合
		Map<Phone,String> hm = new HashMap<Phone,String>();

		//往集合中添加元素
		hm.put(new Phone("苹果","iPhone6"),"美国");
		hm.put(new Phone("三星","s6"),"韩国");
		hm.put(new Phone("小米","红米"),"中国");
		hm.put(new Phone("诺基亚","砸核桃神器"),"芬兰");
		hm.put(new Phone("魅族","M1"),"中国");
		hm.put(new Phone("苹果","iPhone6"),"中国山寨");

		//取出集合中的元素
		Set<Phone> keySet = hm.keySet();

		Iterator<Phone> it = keySet.iterator();

		while(it.hasNext())
		{
			//用Phone类型变量接收key
			Phone key = it.next();
			//用get方法获取value
			String value = hm.get(key);
			//输出键和值
			System.out.println(key+",产地:"+value);		
		}
	}
}


                        运行结果



                  练习二

/*
Map集合练习二

对学生对象的年龄进行升序排序。

学生都有自己的籍贯,所以
key = 学生     value = 籍贯

因为学生和籍贯是以键值对的形式存在的,所以用Map集合

在这里我们使用TreeSet
*/

import java.util.*;

//创建学生类
class 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;
	}

	//具体的复写过程我就不多讲解了,复写了这么多次,大家应该懂了~~
	//复写hashCode方法
	public int hashCode()
	{
		return name.hashCode()+age*18;
	}
	//复写equals方法
	public boolean equals(Object obj)
	{
		if(!(obj instanceof Student))
			throw new RuntimeException("类型不批陪");
		Student s = (Student)obj;
		return this.name.equals(s.name) && this.age == s.age;	
	}
}

class  MapTest2
{
	public static void main(String[] args) 
	{
		//创建Map集合对象,并把比较器对象作为参数传入
		Map<Student,String> tm = new TreeMap<Student,String>(new myComparator());

		//添加元素
		tm.put(new Student("pt546",21),"Beijing");
		tm.put(new Student("pt03",23),"Shanghai");
		tm.put(new Student("pt546",21),"Guangzhou");
		tm.put(new Student("pt1",24),"Shenzhen");
		tm.put(new Student("pt0001",22),"Tianjin");

		//取出元素
		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 key = me.getKey();
			String value = me.getValue();

			System.out.println(key+"......"+value);
		
		}
	}
}

//建立一个比较器用于对年龄进行排序
class myComparator implements Comparator<Student>
{
	public int compare(Student s1 , Student s2)
	{
		//先用compareTo比较年龄的值,并用int类型的变量记录住
		int num = new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
		//如果num一样,说明两个学生年龄一样,再按名字比较
		if(num==0)
			return s1.getName().compareTo(s2.getName());
		//如果num!=0,返回num的值
		return num;
	}
}


                        运行结果



 

                  练习三

/*
Map练习三

"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数。
希望打印结果:a(1)c(2).....

看到希望打印结果这句,我就想到了映射,因为他们存在着映射关系,
每个字母都对应着它出现的次数。

所以这里采用Map集合

思路
1.将字符串转成字符数组
2.定义一个Map集合,因为打印的结果字母要有顺序,所以用TreeMap
3.遍历数组,将每一个字母都作为键用,,get方法去Map集合中查
	如果返回null,就将该字母作为键和1作为值存入到Map集合中。
	如果返回的不是null,就说明该字母已经作为键存在在Map集合中,并有对应的值
	那么就获取该字母对应的值,并进行自增,然后将该字母和自增后的次数作为
	一个键值对再存入集合中,覆盖原键对应的值
4.将Map中的元素按题意打印形式返回

虽然我用的是毕老师上课讲过的题,但我的代码都不是复制粘贴,是纯手打哦~
写个博客不容易啊!所有程序都手打,不过现在打代码速度快多了,熟能生巧 嘿嘿

*/
import java.util.*;
class  MapTest3
{
	public static void main(String[] args) 
	{
		//要被计数的字符串
		String s = "sd+++fgz0x c/v*asdfxcvdf";

		//调用获取字母个数的方法,并输出结果
		System.out.println(getCharCount(s));
	}
	//为了使主函数看起来不臃肿,单独封装获取字母个数方法
	public static String getCharCount(String s)
	{
		//先将字符串变成字符数组
		char[] arrc = s.toCharArray();

		//定义一个TreeMep集合
		TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();

		//定义一个计数器
		int count = 0;
		//遍历数组
		for(int i=0 ; i<arrc.length ; i++)
		{
			//先判断字符数组内的元素是否都是字母如果不是的话,则不参加计数
			if(!(arrc[i]>='a' && arrc[i]<='z' || arrc[i]>='A' && arrc[i]<='Z'))
				//如果是,程序继续
				continue;

			//通过getValue方法获取数组中元素对应的值,并用Integer类型变量接收
			Integer value = tm.get(arrc[i]);
			//如果value!=null,说明这个键已经存在
			if(value!=null)
				//用count将value的值记住
				count = value;

			//否则就是value==null,所以直接让count自增,上面的判断语句运行完也会执行自增
			count++;

			//将arrc[i]作为键,count作为值存入Map集合中,如果原来集合中没有arrc[i]键,
			//就是新增加了一个键,如果有,就用新的值替代旧的值
			//为什么count是int型的可以作为键存入Map集合?
			//因为JDK1.5版本之后,自动装箱
			tm.put(arrc[i],count);
		}

		//创建一个StringBuilder容器
		//主要目的是可以让输出的结果符合题意
		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 key = me.getKey();
			Integer value = me.getValue();
			//将键和值存入StringBuilder容器中
			sb.append(key+"("+value+")");
		}
		//使用toString方法,将StringBuilder容器中的数组转换为字符串,并返回
		return sb.toString();
	}
}


                        运行结果



 

      

      Map扩展知识


            Map集合被使用是因为具备映射关系。在很多项目中,应用比较多的是一对多的映射关系,


                  这就可以通过嵌套的形式将多个映射定义到一个大的集合中,并将大的集合分级处理,形成一个体系。

 

            如下面的程序所示

/* 
map扩展知识。 

map集合被使用是因为具备映射关系。 
以下是班级对应学生,而学生中学号对应着姓名的映射关系: 
"jichuban"   "01" "pt1";   
"jichuban"   "02" "pt2"; 
     
"jiuyeban"   "01" "pjz1"; 
"jiuyeban"   "02" "pjz2"; 
     
就如同一个学校有多个教室。每一个教室都有名称。 
*/  
import java.util.*;  
      
class  MapExpand
{  
	public static void main(String[] args)   
	{  
		//基础班集合  
		HashMap<String,String> jiChuBan=new HashMap<String,String>();  
		//就业班集合  
		HashMap<String,String> jiuYeBan=new HashMap<String,String>();  
		//学校集合  
		HashMap<String,HashMap<String,String>> hM=new HashMap<String,HashMap<String,String>>();  
					  
		//将班级名称作为键,不同班级学生作为值传入学校集合中。  
		hM.put("jichuban",jiChuBan);  
		hM.put("jiuyueban",jiuYeBan);  
					  
		//将学号作为键,姓名作为值,传入基础班集合中 
		jiChuBan.put("01","pt1");  
		jiChuBan.put("02","pt2");  
					  
		//将学号作为键,姓名作为值,传入就业班集合中  
		jiuYeBan.put("01","pjz1");  
		jiuYeBan.put("02","pjz2");  
						  
		//直接输出所有学生的信息 
		getAllStudentInfo(hM);  
			  
	}  
	//定义一个方法获取全部学生的信息,在哪个班级,名字,学号 
	public static void getAllStudentInfo(HashMap<String ,HashMap<String,String>> hM)  
	{  
		//迭代Map集合
		for (Iterator<String> it=hM.keySet().iterator();it.hasNext() ; )
		{  
			//用String类型变量接收班级名称
			String s= it.next();
			System.out.println(s+":");  
			//根据get方法获取班级的集合
			HashMap<String,String> stu=hM.get(s);
			
			//调用获取学生信息方法
			getStudentInfo(stu);  
		}  
	}  
			  
	//获取班级中学生的信息,包括姓名和学号  
	public static void getStudentInfo(HashMap<String,String> stu)  
	{  
		//遍历班级集合
		for (Iterator<String> it=stu.keySet().iterator();it.hasNext() ; )  
		{  
			//获取学号,姓名
			String key=it.next();  
			String value=stu.get(key);
			System.out.println(key+"..."+value);  
		}  
	}  
}  


                  运行结果



      

      那么现在问题来了,挖掘机技术。。。。。额不对,我们学习了这么多集合,那到底具体要用谁呢?

        

            看一张我手画图就知道啦



 

         按上图分析就好。果然按和毕老师说的一样,课学下来,画图用的还是不错的。



 



谢谢大家观看~

-----------android培训java培训、java学习型技术博客、期待与您交流!---------

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值