Java——集合容器


集合框架

集合类:
      面向对象编程中会出现很多的对象,为了方便这些对象的存储,便出现了集合框架。集合框架可以存储和操作多个对象,而它和数组的不同是在于,数组只能存储同一类型的对象,而集合可以存储不同类型的对象,而且集合的长度可以是任意的。
      集合框架中有很多中容器,用来存储对象。为什么会出现这么多容器呢?是因为每一个容器对对象的存储方式都不同,这种存储方式称为数据结构。

Collection类:
     Collection
         |--List//元素是有序的,元素可以重复。因为该集合体系有索引。
         |--Set//元素是无序的,元素不可以重复。

Collection类中常见方法:
添加元素
        add(Object obj); 
删除元素
        remove(Object obj);
        removeAll(集合);//删除参数集合中有的元素
        clear();//清空集合
判断元素
        contains(Object obj);//是否包含参数
        isEmpty();//判空
获取集合长度
       size();
取交集
       retainAll(集合);//取和参数集合的交集


迭代器
迭代器就是用来从集合中取出元素的方式。而迭代器被定义成内部类的形式,是因为Collection中有很多不同的子容器,这些子容器的数据结构不同,对元素的取出方式也不一样,但对外都提供了Iterator()方法进行取出操作。
迭代器的常见方法:
      hasNext();//判断是否有下一个元素
      next();//取出下一个元素
      remove();//移除元素
遍历取出元素时,用循环判断hasNext()进行取出。推荐使用for循环,因为for循环中的迭代器是局部变量,循环后就会在内存中清除,写法如下:
for(Iterator it = a.iterator();it.hasNext();  )
{
           System.out.println(it.next());
}

List类:
       元素是有序的,元素可以重复。因为该集合体系有索引。
list类的特有方法:list类方法的特点是对索引进行操作。
  增
      add(index,element);//在指定位置添加元素
      addAll(index,Collection);//在指定位置增加给定集合中的元素
  删
      remove(index);//删除指定位置的元素
  改
      set(index,element);//修改指定位置的元素。
  查
      get(index);//通过索引获取元素
      subList(from,to);//获取子集的对象元素

List的三个子类
     1. ArrayList
     2.LinkedList
     3.Vector
List集合判断元素是否相同,移除等操作,依据的是元素的equals方法。

ArrayList:
    对应的数据结构是顺序表,查询速度快,增删速度慢。线程不同步。
Vector:
    和ArrayList数据结构相同,因线程同步被ArrayList取代。
LinkedList:
    对应的数据结构是链表,增删速度快,查询速度慢。

ListIterator:
    它定义了针对于List数据结构的特有方法:
     add(obj); //增加
     set(obj); //修改为obj
     hasPrevious(); //判断前面是否有元素

Enumeration:
    相当于Vector的迭代器。
    特有方法:
         addElement(obj);//相当于add(obj);
         Enumerationelements();//Vector的取出元素方式
         hasMoreElements();//相当于Iterator的hasNext()方法
         nextElements();//相当于Iterator的next()方法
    
LinkedList:
     特有方法:因为链表增删操作繁琐,所以只有从头和从尾的增删方法。
     增
         addFirst();
         addLast();
     查
        getFirst();
        getLast();
     删
         removeFirst();
         removeLast();
    查找和删除方法都会返回当前元素,如果没有获取到元素,则抛出NoSuchElementException。
在JDK1.6以后,出现了替代方法。
     增
        offFirst();
        offLast();
     获取
        peekFirst();
        peekLast();
     删
        pollFirst();
        pollLast();
    同上,查找和删除方法都会返回当前元素,如果没有获取到元素,则返回null。


下面一个List集合的练习:
首先是LinkedList练习,用LinkedList实现队列和栈的存取操作。代码如下:
        
class MyQueue//队列结构元素存取顺序是FIFO(先进先出)
{
	private LinkedList link;
	public MyQueue()
	{
		link = new LinkedList();
	}
	
	public void push(Object obj)
	{
		link.add(obj);
	}
	public Object pop()
	{
		return link.removeLast();
	}
	public boolean isNull()
	{
		return link.isEmpty();
	}
}

class MyStack//栈结构存取顺序是FILO(先进后出)
{
	private LinkedList link;
	public MyStack()
	{
		link = new LinkedList();
	}
	
	public void push(Object obj)
	{
		link.add(obj);
	}
	public Object pop()
	{
		return link.removeFirst();
	}
	public boolean isNull()
	{
		return link.isEmpty();
	}
}

Set类


在set集合中,元素是无序的,元素不可以重复。   
      常用的子类有两个:
         HashSet,
         TreeSet。

HashSet:
      基于哈希表的Set集合,首先用hashcode()函数保证元素的唯一性, 如果hashcode的结果相同,则用equals()比较元素是否相同。
 下面是HashSet存储自定义元素的程序示例:
import java.util.*;

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 int getAge()
	{
		return age;
	}

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

	public int hashCode()
	{
		return this.name.hashCode()+this.age;
	}
}
class  HashSetTest
{
	public static void main(String[] args) 
	{
		HashSet h=new HashSet();
		h.add(new Person("shenm",10));
		h.add(new Person("shenm2",6));
		h.add(new Person("shenm1",30));
		h.add(new Person("shenm0",10));
		h.add(new Person("shenm0",10));
		
		for (Iterator it=h.iterator(); it.hasNext(); )//取出元素
		{
			Person p=(Person)it.next();
			print(p.getName()+"..."+p.getAge());
		}

	}

	public static void print(Object obj)
	{
		System.out.println(obj);
	}
}

TreeSet:
       基于的数据结构是二叉树,每次存入元素时对元素进行比较。比较的方法有二,一种是让元素自身具备比较性——就是实现Comparable接口,并覆盖CompareTo(Object obj)方法。第二种是自定义一个比较器类,实现Comparator接口,并覆盖Compare(Object o1, Object o2)方法。这两个函数的返回值是正数、负数、零,分别对应元素的比较结果为——大于、小于、等于。
      下面给出两种比较方法的代码示例:
1、实现Comparable接口
class Person implements Comparable
{
	private String name;
	private int age;
	public Person(String name, int age)
	{
		this.name = name;
		this.age = age;
	}
	
	public String getName()
	{
		return this.name;
	}
	
	public int getAge()
	{
		return this.age;
	}

	@Override
	public int compareTo(Object obj)
	{
		if(!(obj instanceof Person))
			throw new RuntimeException("not a Person");
		Person p = (Person)obj;
		
		System.out.println(this.name + "   compare to   " + p.name);
		if(this.age > p.age)
			return 1 ;
		if(this.age == p.age)
			return this.name.compareTo(p.name);
		return -1;
		
	}
}

class TreeSetTest
{
	public static void main(String args[])
	{
		TreeSet<Person> tr = new TreeSet<Person>();
		
		tr.add(new Person("zhangsan1", 11));
		tr.add(new Person("zhangsan2", 12));
		tr.add(new Person("zhangsan3", 13));
		tr.add(new Person("zhangsan4", 15));
		tr.add(new Person("zhangsan6", 19));
		tr.add(new Person("zhangsan5", 19));
		
		Iterator it = tr.iterator();
		
		while(it.hasNext())
		{
			Person p = (Person)it.next();
			print(p.getName() + "---" + p.getAge());
		}
	}
	public static void print(Object obj)
	{
		System.out.println(obj);
	}
}

2、自定义比较器实现Comparator接口

import java.util.*;

class Person 
{
	private String name;
	private int age;
	public Person(String name, int age)
	{
		this.name = name;
		this.age = age;
	}
	
	public String getName()
	{
		return this.name;
	}
	
	public int getAge()
	{
		return this.age;
	}
}

class TreeSetTest
{
	public static void main(String args[])
	{
		TreeSet<Person> tr = new TreeSet<Person>(new PersonComparator());
		
		tr.add(new Person("zhangsan1", 11));
		tr.add(new Person("zhangsan2", 12));
		tr.add(new Person("zhangsan3", 13));
		tr.add(new Person("zhangsan4", 15));
		tr.add(new Person("zhangsan6", 19));
		tr.add(new Person("zhangsan5", 19));
		
		Iterator<Person> it = tr.iterator();
		
		while(it.hasNext())
		{
			Person p = (Person)it.next();
			print(p.getName() + "---" + p.getAge());
		}
	}
	
	
	public static void print(Object obj)
	{
		System.out.println(obj);
	}
}

class PersonComparator implements Comparator<Person>  
{  
    public int compare(Person p1,Person p2)  
    {  
        int num=new Integer(p1.getName().length()).compareTo(new Integer(p2.getName().length()));  
        if (num==0)  
        {  
            return new Integer(p1.getAge()).compareTo(p2.getAge());  
        }  
        return num;  
    }  
}  



Map类

Map类存放的元素是键值对,同时要保证键的唯一性。

Map类常见的子类有:
       Hashtable
       HashMap
       TreeMap
Hashtable和HashMap都是基于哈希表的集合,HashMap较新,代替了Hashtable,允许存储null值和null键,线程不同步。
TreeMap是基于二叉树的集合。

Map类特有方法:
增:
   put(K key,V value )  //添加元素
   putAll(Map<? extends K , ? extends V> m ) //添加一组元素
删:
   remove(Object  key) //删除指定键值对
   clear() //清空容器
查:
   containsKey(Object key) //是否包含指定键
   containsValue(Object value) //是否包含指定值
   isEmpty() //判空
获取:
   get(Object key) //通过键值获取对应的值
   重要的是下面两个取出方法:
   entrySet() //返回一个元素类型是Map.Entry<K, V>的Set集合,包含Map所有的键值对。
   keySet() //返回一个包含map所以键值的Set集合。

在进行有关集合的练习时,应注意养成将元素都实现Comparable接口和自定义比较器的习惯。

下面是Map集合取出键值对的两种方式:
1、通过entrySet()方法直接返回包含键值对的Set集合:
代码如下:
示例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;
	}
	
	
	@Override
	public int hashCode()
	{
		return name.hashCode() + age * 34;
	}


	@Override
	public boolean equals(Object obj)
	{
		if(!(obj instanceof Student))
			return false;
			//throw new ClassCastException("类型不匹配");
		Student s = (Student)obj;
		return this.name.equals(s.name) && this.age == s.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;
	}
	@Override
	public String toString()
	{
		return "Student [name=" + name + ", age=" + age + "]";
	}

	@Override
	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 MapTest2
{
	public static void main(String[] args)
	{
		TreeMap<Student, String> tm = new TreeMap<Student, String>(new StuNameComparator());
		
		tm.put(new Student("lisi03", 24), "武汉");
		tm.put(new Student("lisi01", 22), "北京");
		//tm.put(new Student("lisi01", 21), "天津");
		tm.put(new Student("lisi04", 23), "南京");
		tm.put(new Student("lisi02", 21), "上海");
		
		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 s = me.getKey();
			String addr = me.getValue();
			print(s + "--" + addr);

		}
	}
	
	public static void print(Object obj)
	{
		System.out.println(obj);
	}
}

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

2、第二种方法是用keySet()方法返回包含键值的Set,然后用get方法一次取出对应的值。
代码如下:(学生类定义部分不再给出)
class MapTest
{
	public static void main(String[] args)
	{
		HashMap<Student, String> hm = new HashMap<Student, String>();
		
		hm.put(new Student("lisi01", 21), "北京");
		hm.put(new Student("lisi01", 21), "天津");
		hm.put(new Student("lisi02", 22), "上海");
		hm.put(new Student("lisi03", 23), "武汉");
		hm.put(new Student("lisi04", 24), "南京");

		Iterator<Student> it1 = hm.keySet().iterator();
		while(it1.hasNext())
		{
			Student s = it1.next();
			String addr = hm.get(s);
			print(s + ".." + addr);
		}
	}
	
	public static void print(Object obj)
	{
		System.out.println(obj);
	}
}

Map扩展知识:
   Map的映射关系不仅可以建立在单个元素之间,也可以建立在集合与元素,集合与集合之间,这样就形成了映射关系的嵌套。
   比如传智播客体系,可以分为预热班,就业班,每个班中又有学生元素,学生可以有学号和姓名的映射关系。

给出代码示例:

import java.util.*;

class  MapExpandKnow
{
	public static void main(String[] args) 
	{
		//预热班
		HashMap<String,String> yureban=new HashMap<String,String>();
		//就业班
		HashMap<String,String> jiuyeban=new HashMap<String,String>();
		//传智播客
		HashMap<String,HashMap<String,String>> czbk=new HashMap<String,HashMap<String,String>>();
		
	
		czbk.put("yureban",yureban);
		czbk.put("jiuyueban",jiuyeban);
		
		//预热班级中学号与姓名的映射
		yureban.put("01","zhangsan");
		yureban.put("02","lisi");
		
		//就业班级中学号与姓名的映射
		jiuyeban.put("01","wangwu");
		jiuyeban.put("02","zhouqi");
			
			//直接显示全部学生信息
		getInfo(czbk);

	}
	//定义一个方法获取全部学生信息,包括在哪个班级,叫什么名字,学号多少
	public static void getInfo(HashMap<String ,HashMap<String,String>> hm)
	{
		for (Iterator<String> it=hm.keySet().iterator();it.hasNext() ; )
		{
			String s= it.next();
			System.out.println(s+":");
			HashMap<String,String> stu=hm.get(s);
			getStuInfo(stu);
		}
	}
	
	//获取班级中学生的信息,包括姓名和学号
	public static void getStuInfo(HashMap<String,String> hm)
	{
		for (Iterator<String> it=hm.keySet().iterator();it.hasNext() ; )
		{
			String key=it.next();//学号
			String value=hm.get(key);//姓名
			System.out.println(key+"..."+value);
		}
	}
}





泛型
泛型是JDK1.5版本以后出现的新特性。用于解决安全问题,是一个类型安全机制。泛型要求在定义集合时,明确你要在集合中操作何种类型的数据,格式是通过<>来定义要操作的引用数据类型,如ArrayList<String>。这样就可以将运行时期出现的问题ClassCastException,转移到编译时期。方便于程序员解决问题。让运行时期问题减少、安全。同时也避免了强制转换的麻烦。 当传入的类型不确定时,可以使用通配符?,也称为占位符。使用通配符的好处是可以不用明确传入的类型,这样在使用泛型类或者泛型方法时,提高了扩展性。
泛型限定:对泛型的上下限进行限定,明确泛型的范围。
     <? extends E>:可接收E类型或E类型的子类型,称之为上限。
     <? super E>:可接收E类型或E类型的父类型,称之为下限。
泛型类:当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。现在定义泛型来完成扩展。

泛型方法:不同方法如果要操作不同类型的参数,而且类型还不确定,那么可以将泛型定义在方法上。

格式如下:
class Test<T>//泛型类
{
	private T t;
	public void setObject(T t)
	{
		this.t = t;
	}
	public T getObject()
	{
		return t;
	}
	//-----------------泛型方法
	public <E> void print(E e)
	{
		System.out.println(e);
	}
	public <Q> void show(Q q)
	{
		System.out.println(q);
	}
}


class GenericTest
{
	public static void main(String[] args)
	{
		Test<String> t = new Test<String>();
		t.setObject("GG");
		System.out.println(t.getObject());
		
		t.show(4);
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值