Java面向对象 集合(下)



 Java面向对象 集合(下)


知识概要:

              (1)Map集合的体系结构

              (2)Map集合的方法

              (3)HashMap TreeMap

              (4)集合框架中的常用工具类

              (5)高级for循环


Map集合的体系结构

        Map
              |--Hashtable:   底层是哈希表数据结构,不可以存入null键null值。   该集合是线程同步的。jdk1.0.效率低。
              |--HashMap: 底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代  

              |--TreeMap:  底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

Map集合的常用方法

 1,添加。


       put(K key, V value)
       putAll(Map<? extends K,? extends V> m)

 2,删除。


       clear()
       remove(Object key)

 3,判断。


      containsValue(Object value)
      containsKey(Object key)
      isEmpty()

4,获取。


     get(Object key)
     size()
     values()


import java.util.*;
class  MapDemo
{
	public static void main(String[] args) 
	{
		Map<String,String> map = new HashMap<String,String>();

		//添加元素,添加元素,如果出现添加时,相同的键。那么后添加的值会覆盖原有键对应值。
		//并put方法会返回被覆盖的值。
		System.out.println("put:"+map.put("01","zhangsan1"));
		System.out.println("put:"+map.put("01","wnagwu"));
		map.put("02","zhangsan2");
		map.put("03","zhangsan3");

		System.out.println("containsKey:"+map.containsKey("022"));
		//System.out.println("remove:"+map.remove("02"));

		System.out.println("get:"+map.get("023"));

		map.put("04",null);
		System.out.println("get:"+map.get("04"));
		//可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断。


		
		//获取map集合中所有的值。
		Collection<String> coll = map.values();

		System.out.println(coll);
		System.out.println(map);


	}
}


map集合的两种取出方式:


 1,Set<k> keySet:将map中所有的键存入到Set集合。因为set具备迭代器。
       所有可以迭代方式取出所有的键,在根据get方法。获取每一个键对应的值。
     
 Map集合的取出原理:将map集合转成set集合。在通过迭代器取出。


2,Set<Map.Entry<k,v>> entrySet:将map集合中的映射关系存入到了set集合中,
      而这个关系的数据类型就是:Map.Entry

      Entry其实就是Map中的一个static内部接口。
      为什么要定义在内部呢?
      因为只有有了Map集合,有了键值对,才会有键值的映射关系。
      关系属于Map集合中的一个内部事物。
      而且该事物在直接访问Map集合中的元素。

import java.util.*;


class MapDemo2 
{
	public static void main(String[] args) 
	{
		Map<String,String> map = new HashMap<String,String>();

		map.put("02","zhangsan2");
		map.put("03","zhangsan3");
		map.put("01","zhangsan1");
		map.put("04","zhangsan4");

		//将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);

		}

		/*
		//先获取map集合的所有键的Set集合,keySet();
		Set<String> keySet = map.keySet();

		//有了Set集合。就可以获取其迭代器。
		Iterator<String> it = keySet.iterator();

		while(it.hasNext())
		{
			String key = it.next();
			//有了键可以通过map集合的get方法获取其对应的值。
			String value  = map.get(key);
			System.out.println("key:"+key+",value:"+value);
		}

		*/

	}
}

<strong>/*
每一个学生都有对应的归属地。
学生Student,地址String。
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性



1,描述学生。

2,定义map容器。将学生作为键,地址作为值。存入。

3,获取map集合中的元素。

*/

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 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;
	}

	public int hashCode()
	{
		return name.hashCode()+age*34;
	}
	public boolean equals(Object obj)
	{
		if(!(obj instanceof Student))
			throw new ClassCastException("类型不匹配");

		Student s = (Student)obj;

		return this.name.equals(s.name) && this.age==s.age;
		

	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
	public String toString()
	{
		return name+":"+age;
	}
}



class  MapTest
{
	public static void main(String[] args) 
	{
		HashMap<Student,String> hm = new HashMap<Student,String>();

		hm.put(new Student("lisi1",21),"beijing");
		hm.put(new Student("lisi1",21),"tianjin");
		hm.put(new Student("lisi2",22),"shanghai");
		hm.put(new Student("lisi3",23),"nanjing");
		hm.put(new Student("lisi4",24),"wuhan");

		//第一种取出方式 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 = hm.entrySet();

		Iterator<Map.Entry<Student,String>> iter = entrySet.iterator();
		
		while(iter.hasNext())
		{
			Map.Entry<Student,String> me = iter.next();
			Student stu = me.getKey();
			String addr = me.getValue();
			System.out.println(stu+"........."+addr);
		}
	}
}
</strong>


 集合工具类


集合框架的工具类。
            Collections:集合框架的工具类。里面定义的都是静态方法。
Collections和Collection有什么区别?

Collection是集合框架中的一个顶层接口,它里面定义了单列集合的共性方法。它有两个常用的子接口,
           List:对元素都有定义索引。有序的。可以重复元素。
           Set:不可以重复元素。无序。

Collections是集合框架中的一个工具类。该类中的方法都是静态的
         提供的方法中有可以对list集合进行排序,二分查找等方法。
         通常常用的集合都是线程不安全的。因为要提高效率。
         如果多线程操作这些集合时,可以通过该工具类中的同步方法,将线程不安全的集合,转换成安全的。


  Collections.shuffle(list);                                                将集合打乱顺序

   Collections.reverseOrder(new StrLenComparator())  将集合的比较器反向比较
  Collections.replaceAll(list,"aaa","pp");                        将集合中“aaa”替换成“pp”
  Collections.reverse(list);                                                将集合反向
  Collections.fill(list,"pp");                                                将集合全部替换成pp
  Collections.sort(list,new StrLenComparator());           将集合按照指定比较器排序


 Arrays:

    用于操作数组的工具类。
    
里面都是静态方法。            asList:将数组变成list集合

   把数组变成list集合有什么好处?
 
  可以使用集合的思想和方法来操作数组中的元素。

  注意:将数组变成集合,不可以使用集合的增删方法。
  因为数组的长度是固定。

  如果数组中的元素都是对象。那么变成集合时,数组中的元素就直接转成集合中的元素。
  如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。


集合变数组。
Collection接口中的toArray方法。

<strong>/*
集合变数组。
Collection接口中的toArray方法。


*/
import java.util.*;
class  CollectionToArray
{
	public static void main(String[] args) 
	{
		ArrayList<String> al = new ArrayList<String>();

		al.add("abc1");
		al.add("abc2");
		al.add("abc3");
		
		/*
		1,指定类型的数组到底要定义多长呢?
		当指定类型的数组长度小于了集合的size,那么该方法内部会创建一个新的数组。长度为集合的size。
		当指定类型的数组长度大于了集合的size,就不会新创建了数组。而是使用传递进来的数组。剩余的数组位置为null
		所以创建一个刚刚好的数组最优。
		

		2,为什么要将集合变数组?
		为了限定对元素的操作。不需要进行增删了。

		*/

		String[] arr = al.toArray(new String[al.size()]);

		System.out.println(Arrays.toString(arr));



	}
}
</strong>



高级for循环
    
   格式:
      for(数据类型 变量名 : 被遍历的集合(Collection)或者数组)
    
{
    
     }

    对集合进行遍历。
   只能获取集合元素。但是不能对集合进行操作。
   迭代器除了遍历,还可以进行remove集合中元素的动作。
   如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。
   传统for和高级for有什么区别呢?
   高级for有一个局限性。必须有被遍历的目标。
   建议在遍历数组的时候,还是希望是用传统for。因为传统for可以定义脚标。


import java.util.*;

class ForEachDemo 
{
	public static void main(String[] args) 
	{

		
		ArrayList<String> al = new ArrayList<String>();

		al.add("abc1");
		al.add("abc2");
		al.add("abc3");


		for(String s : al)
		{
			//s = "kk";
			System.out.println(s);
		}

		System.out.println(al);
		/*
		Iterator<String> it = al.iterator();

		while(it.hasNext())
		{
			System.out.println(it.next());
		}
		*/

		int[] arr = {3,5,1};

		for(int x=0; x<arr.length; x++)
		{
			System.out.println(arr[x]);
		}
		for(int i : arr)
		{
			System.out.println("i:"+i);
		}


		HashMap<Integer,String> hm = new HashMap<Integer,String>();

		hm.put(1,"a");
		hm.put(2,"b");
		hm.put(3,"c");

		Set<Integer> keySet = hm.keySet();
		for(Integer i : keySet)
		{
			System.out.println(i+"::"+hm.get(i));
		}

//		Set<Map.Entry<Integer,String>> entrySet = hm.entrySet();
//		for(Map.Entry<Integer,String> me : entrySet)

		for(Map.Entry<Integer,String> me : hm.entrySet())
		{
			System.out.println(me.getKey()+"------"+me.getValue());
		}

	}
}

0

首先要明白一点:加入Set里面的元素必须定义equals()方法以确保对象的唯一性。

第一个问题:TreeSet是怎么实现有序的,它是按什么规则排序的?
TreeSet的底层实现是采用红-黑树的数据结构,采用这种结构可以从Set中获取有序的序列,但是前提条件是:元素必须实现Comparable接口,该接口中只用一个方法,就是compareTo()方法。当往Set中插入一个新的元素的时候,首先会遍历Set中已经存在的元素(当然不是采用顺序遍历,具体采用什么方法,建议自己去看看源码),并调用compareTo()方法,根据返回的结果,决定插入位置。进而也就保证了元素的顺序。


第二个问题:它们怎么保证元素的不重复,是根据什么判断两个元素相同而不再添加的呢?
上面已经说过,加入Set里面的元素必须定义自己的equals()方法,但是对于良好的设计风格,最好在覆盖equals()方法的同时,也覆盖hashCode()方法,当然,对于TreeSet而言不用覆盖hashCode()方法也可。请记住:覆盖hashCode()方法的目的,只有一个原因就是提高效率。

在往Set中插入新的对象时,首先会用该对象的hashCode()与已经存在对象的hashCode()做比较,如果相等,那就不能插入,如果不等,才会调用equals()方法,如果equals结果为true,说明已经存在,就不能再插入,如果为false,可以插入。

注:如果没有覆盖hashCode()方法,那就是只比较equals().对两个对象equals运算,是判断两个对象是否相等的关键






posted @ 2014-05-30 19:21  博客园杀手  阅读(209)  评论(0编辑  收藏  举报