黑马程序员,Java基础知识七:集合类

collection集合

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,于是就出现了集合类。集合类不同于数组,数组虽然也可以存储对象,但长度是固定的,集合长度是可变的。数组只可以存储基本数据类型,而集合中可以存储自定义的对象。

collection集合体系:

 |-----List:元素是有序的,元素可以重复。因为该集合体系有索引。
        |-------ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
        |-------LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
        |-------Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。

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

        |-------HashSet:数据结构是哈希表。线程是非同步的。保证元素唯一性的原理:判断元素的hashCode值是否相同, 如果相同,还会继续判断元素的equals方法,是否为true。
        |-------TreeSet:可以对Set集合中的元素进行排序,底层数据结构是二叉树,保证元素唯一性的依据: compareTo方法return 0.

在集合Collection中定义了集合框架的共性功能。
1,添加add(e);addAll(collection);
2,删除
    remove(e);removeAll(collection);clear();
3,判断。
    contains(e); isEmpty();
4,获取
    iterator();size();
5,获取交集。
    retainAll();
6,集合变数组。
    toArray();

注意:

1,add方法的参数类型是Object。以便于接收任意类型对象。
2,集合中存储的都是对象的引用(地址)

迭代器

迭代器是集合的取出元素的方式。如同抓娃娃游戏机中的夹子。迭代器是取出方式,会直接访问集合中的元素。所以将迭代器通过内部类的形式来进行描述。通过容器的iterator()方法获取该内部类的对象。

class  CollectionDemo
{
	public static void main(String[] args) 
	{
		
		method_get();
	}
	public static void method_get()
	{
		ArrayList al = new ArrayList();
		al.add("java01");
		al.add("java02");
		al.add("java03");
		al.add("java04");
		for(Iterator it = al.iterator(); it.hasNext() ; )
		{
			sop(it.next());
		}
	}
	public static void method_2()
	{
		ArrayList al1 = new ArrayList();
		al1.add("java01");
		al1.add("java02");
		al1.add("java03");
		al1.add("java04");
		ArrayList al2 = new ArrayList();
		al2.add("java03");
		al2.add("java04");
		al2.add("java05");
		al2.add("java06");	
		//al1.retainAll(al2);//去交集,al1中只会保留和al2中相同的元素。
		al1.removeAll(al2);
		sop("al1:"+al1);
		sop("al2:"+al2);
	}

	public static void base_method()
	{
		//创建一个集合容器。使用Collection接口的子类。ArrayList
		ArrayList al = new ArrayList();

		//1,添加元素。
		al.add("java01");//add(Object obj);
		al.add("java02");
		al.add("java03");
		al.add("java04");

		//打印原集合。
		sop("原集合:"+al);


		//3,删除元素。
		//al.remove("java02");
		//al.clear();//清空集合。


		//4,判断元素。
		sop("java03是否存在:"+al.contains("java03"));
		sop("集合是否为空?"+al.isEmpty());


		//2,获取个数。集合长度。
		sop("size:"+al.size());

		//打印改变后的集合。
		sop(al);

	}

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

注意:

1,迭代器在Collection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。

2,在操作迭代器的时候不要同时操作集合的方法,会有异常,可以操作迭代器iterator的方法去操作元素,有判断,取出,删除等操作。使用其子接口ListIterator则增删改查的功能全可以实现。

3,迭代器的next方法是自动向下取元素的,要避开出现NoSuchElementException异常。

4,迭代器的next方法返回值类型是Object,所以要记得类型转换。

ArrayList

Collection中最常见的两个子接口:list和set,list里存放元素是有序的,可重复存放元素,而set中的元素是无序的,而且不可以存放重复元素。ArrayList实现了list接口,它的底层是数组数据结构,特点是:查询快,增删慢,线程不安全。

在Arraylist中有一些集合特有的方法,凡是可以操作角标的方法都是该体系特有的方法:

1,增加add(index,element),addAll(index,collection)

2,删除remove(index)

3,修改set(index,element)

4,查找get(index),sublist(from,to),ListIterator(),int indexOf(obj)。(获取指定元素的位置。)

去除ArrayList集合中的重复元素。

class ArrayListTest 
{

	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
	public static void main(String[] args) 
	{
		ArrayList al = new ArrayList();

		al.add("java01");
		al.add("java02");
		al.add("java01");
		al.add("java02");
		al.add("java01");

		sop(al);
		
		al = singleElement(al);

		sop(al);
		

	}

	public static ArrayList singleElement(ArrayList al)
	{
		//定义一个临时容器。
		ArrayList newAl = new ArrayList();

		Iterator it = al.iterator();

		while(it.hasNext())
		{
			Object obj = it.next();

			if(!newAl.contains(obj))
				newAl.add(obj);

		}

		return newAl;
	}
}

LinkedList

linkedlist的底层是链表数组结构,特点是,增删快,查询慢。

linkedlist也有一些特有的方法:

1,增加addFirst(),addLast();
2,两种获取getFirst(),getLast(),获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException
removeFirst();removeLast();获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException

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

offerFirst(),offerLast(),增加元素。
peekFirst(),peekLast(),获取元素,但不删除元素。如果集合中没有元素,会返回null。
pollFirst(),pollLast(),获取元素,但是元素被删除。如果集合中没有元素,会返回null。

class LinkedListDemo 
{
	public static void main(String[] args) 
	{
		LinkedList link = new LinkedList();

		link.addLast("java01");
		link.addLast("java02");
		link.addLast("java03");
		link.addLast("java04");

		while(!link.isEmpty())
		{
			sop(link.removeLast());
		}

	}

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

vector

vector的底层也是数组结构,它可以算是集合界的元老了,在1.1时代已经存在,它是支持线程同步的,但随着API不断升级,它逐渐的被Arraylist替代了。

枚举是Vector特有的取出方式,我们可以发现枚举和迭代器很像,实质上枚举和迭代是一样的,但因为枚举的名称以及方法的名称都过长,所以被迭代器取代了,因此枚举郁郁而终了。

class VectorDemo 
{
	public static void main(String[] args) 
	{
		Vector v = new Vector();

		v.add("java01");
		v.add("java02");
		v.add("java03");
		v.add("java04");

		Enumeration en = v.elements();

		while(en.hasMoreElements())
		{
			System.out.println(en.nextElement());
		}
	}
}

HashSet

HashSet的底层实现了哈希表的数据结构,它是不支持线程同步的。

HashSet因为实现了Set接口,它的元素也是无序存放的,也不能存放重复元素,但它要怎么保证元素的唯一性呢?答:通过元素的两个方法,hashCode和equals来完成。当元素的HashCode值相同,才去判断equals是否为true。而元素的hashcode值不同时,就不会调用equals。

注意:

对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。

class HashSetDemo 
{
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
	public static void main(String[] args) 
	{
		
		HashSet hs = new HashSet();

		sop(hs.add("java01"));
		sop(hs.add("java01"));
		hs.add("java02");
		hs.add("java03");
		hs.add("java03");
		hs.add("java04");

		Iterator it = hs.iterator();

		while(it.hasNext())
		{
			sop(it.next());
		}
	}
}

TreeSet

Treeset的底层数据结构是二叉树结构,它保证元素唯一性的依据是:在添加元素时,通过元素的CompareTo方法,查看return值是否为0判断是否有重复值,也同时实现了元素的排序。

TreeSet同样实现了Set接口,它与HashSet所不同的是,它可以对Set集合中的元素进行排序。另外TreeSet集合与Hash值没有什么关系。

TreeSet实现排序功能的第一种方法:

让元素自身具备可比性,即元素本身需要实现comparable接口,并要覆盖CompareTo,实现了comparable接口后元素的排序被称为元素的自然顺序或者默认顺序,是升序的。

TreeSet实现排序功能的第二种方法:

当元素自身不具备可比性时,或者具备的可比性不是所需要的时,我们应该让集合自身具备可比性。定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。方法是:定义一个类,实现comparator接口,并覆盖compareTo方法,然后把这个类作为集合构造函数的参数传入,就完成了一个带有可比性的集合了。而当两种排序都存在时,以比较器的排序方法为主。

class TreeSetDemo 
{
	public static void main(String[] args) 
	{
		TreeSet ts = new TreeSet();

		ts.add(new Student("lisi02",22));
		ts.add(new Student("lisi007",20));
		ts.add(new Student("lisi09",19));
		ts.add(new Student("lisi08",19));
		//ts.add(new Student("lisi007",20));
		//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 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)
	{

		//return 0;
		
		if(!(obj instanceof Student))
			throw new RuntimeException("不是学生对象");
		Student s = (Student)obj;

		System.out.println(this.name+"....compareto....."+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;
	}
}


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() , entrySet() , keySet()

Map集合体系

   |-----Hashtable:底层是哈希表数据结构,不可以存入null键null值。该集合是线程同步的。jdk1.0.效率低,已被HashMap替代。
   |-----HashMap:底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。jdk1.2.效率高。
   |-----TreeMap:底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。

我们可以发现,Map集合和Set集合很像,实质上Set底层使用了Map集合。

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

HashMap

HashMap的底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。jdk1.2.效率高。

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

		*/

	}
}

TreeMap

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

当需要对map集合中的元素进行排序时,我们可以用TreeMap

import java.util.*;

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


class  MapTest2
{
	public static void main(String[] args) 
	{
		TreeMap<Student,String> tm = new TreeMap<Student,String>(new StuNameComparator());

		tm.put(new Student("blisi3",23),"nanjing");
		tm.put(new Student("lisi1",21),"beijing");
		tm.put(new Student("alisi4",24),"wuhan");
		tm.put(new Student("lisi1",21),"tianjin");
		tm.put(new Student("lisi2",22),"shanghai");

		
		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 stu = me.getKey();
			String addr = me.getValue();
			System.out.println(stu+":::"+addr);
		}
	}
}

Collections工具类

Collections集合框架的工具类,它里面定义的都是可以操作集合的静态方法。

Collections与Collection的区别

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

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

Collections里的常用方法:

sort(),给集合排序,不定义时按自然顺序排序,也即升序,但该方法不可以对treeSet和treeMap使用。因为这两个集合里已经有自己的排序方式。

max(),求取最值,它与sort都可以自定义一个comparator

fill(),让所有的元素都替换成指定元素

replaceAll(),将集合里元素的某一值全部替换成另一个值。

reverse(),反转,让原来的顺序调反。

reverseOrder(),返回一个比较器,可以强行反转顺序,也可以强行反转指定比较器的顺序。

synchronizedList(),传入一个非同步的list,返回一个同步的list。

swap(),交换指定位置的元素。

shuffle(),随机排序。

import java.util.*;
class  CollectionsDemo
{
	public static void main(String[] args) 
	{
		sortDemo();

	}



	public static void binarySearchDemo()
	{
		List<String> list = new ArrayList<String>();

		list.add("abcd");
		list.add("aaa");
		list.add("zz");
		list.add("kkkkk");
		list.add("qq");
		list.add("z");
		Collections.sort(list,new StrLenComparator());

		sop(list);

		//int index = Collections.binarySearch(list,"aaaa");
		//int index = halfSearch(list,"cc");
		int index = halfSearch2(list,"aaaa",new StrLenComparator());
		sop("index="+index);
	}

	public static int halfSearch(List<String> list,String key)
	{
		int max,min,mid;
		max = list.size()-1;
		min = 0;

		while(min<=max)
		{
			mid = (max+min)>>1;//  /2;

			String str = list.get(mid);

			int num = str.compareTo(key);
			if(num>0)
				max = mid -1;
			else if(num<0)
				min = mid + 1;
			else
				return mid;
		}
		return -min-1;
	}

	public static int halfSearch2(List<String> list,String key,Comparator<String> cmp)
	{
		int max,min,mid;
		max = list.size()-1;
		min = 0;

		while(min<=max)
		{
			mid = (max+min)>>1;//  /2;

			String str = list.get(mid);

			int num = cmp.compare(str,key);
			if(num>0)
				max = mid -1;
			else if(num<0)
				min = mid + 1;
			else
				return mid;
		}
		return -min-1;
	}

	public static void maxDemo()
	{
		List<String> list = new ArrayList<String>();

		list.add("abcd");
		list.add("aaa");
		list.add("zz");
		list.add("kkkkk");
		list.add("qq");
		list.add("z");
		Collections.sort(list);
		sop(list);
		String max = Collections.max(list/*,new StrLenComparator()*/);
		sop("max="+max);
	}

	public static void sortDemo()
	{
		List<String> list = new ArrayList<String>();

		list.add("abcd");
		list.add("aaa");
		list.add("zz");
		list.add("kkkkk");
		list.add("qq");
		list.add("z");
		
		sop(list);

		//Collections.sort(list);
		Collections.sort(list,new StrLenComparator());
		//Collections.swap(list,1,2);
		sop(list);
		
	}

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


class StrLenComparator implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		if(s1.length()>s2.length())
			return 1;
		if(s1.length()<s2.length())
			return -1;
		return s1.compareTo(s2);
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值