黑马程序员_集合框架(List,Set)

 ----------------- android培训java培训、期待与您交流! ----------





Collection
List:列表。
特点:
  • 有序(存储元素的顺序和取出元素的顺序一致)
  • 该集合中的元素都有索引,所以可以通过索引(角标)来访问元素。 
  • 它可以存储重复元素。 
  • 常见子类对象:记住:具体的子类对象,我们要学习应该是该对象的特有的数据结构,以及相关的特点。
  • Vector:jdk1.0就存在了。底层是数组结构的。可变长度数组,
  • 原理:一旦原数组长度不够,会创建新数组,将原数组的元素复制到新数组中,并将新元素添加到新数组中。
  • Vector是同步的。
  • ArrayList:底层是数组结构,也是支持长度可变数组的。是不同步的。替代了Vector.因为效率高。 查询效率很高。 但是增删的效率很低。
  • LinkedList:底层是链接列表结构,简称链表结构。是不同步的。这个中结构的好处:对元素的增删非常效率很高。 查询的效率很低。
  • Set:集:中的方法和Collection一致,只要重点注意它的子类对象即可。取出元素只能使用迭代器。
特点:
  • 不包含重复元素。(最大的特点)
  • 这个集合存入元素的顺序和取出元素的顺序不一定一致。(具体的容器对象数据结构不同,顺序也有不同)
  • HashSet:底层数据结构是哈希表,不保证顺序,是不同步的。
  • 哈希表:提供数组的查询效率而出现的。
  • 将要存储的元素先通过哈希算法算出一个哈希值来标识存储的位置,代表着元素。
  • 要找元素时,先将该元素通过哈希算法算出哈希值,在通过哈希值到哈希表中去查找。
特点:
  • 不关系元素的顺序。
  • 提高了查询效率。
  • 不可能出现重复元素,因为哈希值都不同。即使相同,会再次判断两个元素的equals,内容是否相同。


如果内容也相同,不存,如果内容不同,存储。
所以哈希表要保证元素的唯一性,必须要依赖于两个方法。
1,hashCode
2,equals

TreeSet:可以给Set集合中的元素进行指定顺序的排序。非同步的。 
  • 默认情况下,是通过元素的自然顺序排的序。
  • 它保证元素唯一性的依据是看比较方法的返回结果是否是0.是0.就视为元素相同。不存。


TreeSet排序的方式一:

  • 让元素自身具备比较性,需要实现Comparable接口,覆盖compareTo方法。
  • 这种比较方式成为自然顺序排序。

如果元素自身不具备比较性或者具备的比较性(自然顺序)不是所需要的。

这时只能用第二种方式 。

TreeSet排序的方式二:

  • 让容器自身具备比较性。容器一初始化就具备了比较功能。
  • 因为容器时在对象构造时完成的。通过查阅,有一个构造方法TreeSet(Comparator).
  • 在容器初始化时可以指定一个比较器。 
  • 需要实现Comparator接口,覆盖compare方法即可。
  • 所以这种方式成为比较器排序。 

集合的技巧掌握:
  • 明确具体集合对象名称的后缀:
  • 如果后缀是List,都所属于List体系。通常都是非同步的。
  • 如果后缀是Set,都属于Set体系,通常也是非同步的。
  • 这些体系中的其他子类对象,后缀不是所属接口名的,一般都是同步的。比如Vector.
  • 这在常用子类对象中通用。 

明确数据结构:
  • 对于jdk1.2版本的子类对象。
  • 后缀名是所属的体系。
  • 前缀名是就是数据结构的名称。
比如:
ArrayList: 看到Array,就要明确是数组结构。查询快。
LinkedList:看到Link,就要明确链表结构,就要想到 add get remove 和first last结合的方法.增删快。,

HashSet:

  • 看到hash,就要明确是哈希表。查询巨快,而且唯一性。
  • 想到元素必须覆盖 hashCode方法和equals方法。 

TreeSet:

  • 看到Tree,就要明确是二叉树,可以对元素排序。
  • 就要想到两种排序方式:
自然顺序:Comparable接口,覆盖compareTo(一个参数 )java.lang

比较器:Comparator接口,覆盖compare(两个参数);java.util

判断元素唯一性的依据就是比较方法的返回结果return 0;

演示List子接口中的特有方法。
因为该接口的特点是 对元素有索引标示。
所以它的特有方法应该都是围绕着索引定义的。

1,添加:
void add(index,element);
boolean addAll(index,collection);

2,删除:
object remove(index):获取并删除。记住大家,增加或者删除方法的成功都会改变集合的长度。

3,获取:
获取元素:
Object get(index):获取
获取元素索引:
int indexOf(object);
int lastIndexOf(object);
获取子列表:
List subList(fromIndex,toIndex):获取列表中的一部分,包含fromIndex位置,不包含toIndex位置。

4,修改。
object set(index,element):替换指定位置的元素,并返回被替换掉的元素。
我们发现,List接口是可以对元素进行增删改查的操作的。
注意:只有这个集合具备着增删改查。具备的原因:因为有索引。

演示代码:
package com.itheima.collection;

import java.util.ArrayList;
import java.util.List;

public class Demo3
{

	public static void main(String[] args)
	{
		sop("hello,word!");
		List list = new ArrayList();
		listDemo(list);
	}
	
	public static void listDemo(List list)
	{
		list.add("Demo1");
		list.add("Demo2");
		list.add("Demo3");
		sop("原来集合"+list);
		
		// 插入元素
		list.add("insert00");
		sop(list);
		
		// 删除指定位置元素
		list.remove(2);
		sop(list);
		
		// 获取指定位置的原始
		sop(list.get(1));
		
		// 修改指定位置上的元素
		list.set(1, "set1");
		sop(list);
		
		// 索引元素位置
		sop(list.indexOf("Demo1"));
		
		// 获取子串
		sop(list.subList(0, 2));
	}

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

}

  • 当对集合进行迭代时,在迭代的过程,如果用集合对象对元素进行了修改。
  • 而迭代器是不知道的,所以在迭代的过程中就会发生不确定性。
  • 为了避免这种情况的发生,在迭代时,不要使用集合对象对迭代中的元素进行操作。
  • 但是,我们还想在迭代的过程中对被迭代的元素进行更多的操作。该怎么办呢?
  • 可以使用迭代器的方法。但是Iterator的方法很郁闷,只有判断hasNext,获取next,删除,remove三个方法。
  • 注意:要想解决这个问题,list接口中提供了一个特有的迭代器。
  • 这个迭代器就是ListIterator 列表迭代器。就可以解决这个问题。
  • 介绍一下ListIterator。
  • 它的父接口是Iterator。
  • 一看其方法,add remove set next 它就可以实现在迭代过程中进行元素的增删改查的动作。
  • 它还支持逆向遍历。

注意:这个列表迭代器只能对List集合使用。

vector演示代码:
package com.itheima.collection;

import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;

/**
 * @author mskv
 *
 */
public class VectorDemo
{
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}

	public static void main(String[] args)
	{
		Vector v = new Vector();
		v.add("Demo1");
		v.add("Demo2");
		v.add("Demo3");
		sop(v);
		
/*		for (Iterator it = v.iterator();it.hasNext();)
		{
			sop(it.next());
		}*/
		
		// 枚举和iterator一样,但是iterator多了一个移除操作,枚举只能取vector集合中的元素。
		// 最后枚举被迭代器取代了
		for (Enumeration en = v.elements();en.hasMoreElements();)
		{
			sop(en.nextElement());
		}
	}
}

头尾操作方法。
addFirst();
addLast();
getFirst():从头部获取元素,但不删除。如果没有元素,会抛出NoSuchElementException
getLast();
removeFirst():从头部获取元素,但删除。如果没有元素,会抛出NoSuchElementException
removeLast();

队列模拟:
package com.itheima.collection;
import java.util.LinkedList;

public class QueenDemo
{
	private LinkedList link = null;
	public QueenDemo()
	{
		link = new LinkedList();
	}
	
	public void quAdd(Object obj)
	{
		link.addLast(obj);
	}
	
	public Object quGet()
	{
		return link.removeFirst();
	}
	
	public boolean isEmp()
	{
		return link.isEmpty();
	}
}
package com.itheima.collection;

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

	public static void main(String[] args)
	{
		QueenDemo qd = new QueenDemo();
		qd.quAdd("QueenDemo1");
		qd.quAdd("QueenDemo2");
		qd.quAdd("QueenDemo3");
		
		while (!qd.isEmp())
		{
			sop(qd.quGet());
	
		}
	}
}


ArrayListTest:
package com.itheima.bean;

public class Person
{
	private String name;
	private int age;
	/**
	 * @param name
	 * @param age
	 */
	public Person(String name, int age)
	{
		super();
		this.name = name;
		this.age = age;
	}
	/**
	 * @return the name
	 */
	public String getName()
	{
		return name;
	}
	/**
	 * @param name the name to set
	 */
	public void setName(String name)
	{
		this.name = name;
	}
	/**
	 * @return the age
	 */
	public int getAge()
	{
		return age;
	}
	/**
	 * @param age the age to set
	 */
	public void setAge(int age)
	{
		this.age = age;
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString()
	{
		return "[name=" + name + ", age=" + age + "]";
	}
	
	public boolean equals(Object obj)
	{
		if (!(obj instanceof Person))
			return false;
		Person p = (Person) obj;
		return this.getName().equals(p.getName()) && (this.getAge() == p.getAge());
	}
}
/**
 * 
 */
package com.itheima.collection;

import java.util.ArrayList;
import java.util.Iterator;

import com.itheima.bean.Person;

/**
 * @author mskv
 *
 */
public class ArrayListTest
{
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args)
	{
		ArrayList al = new ArrayList();
		al.add("ArrayListTest0");
		al.add("ArrayListTest1");
		al.add("ArrayListTest2");
		al.add("ArrayListTest3");
		al.add("ArrayListTest2");
		sop(al);
		al = removeRepeatElements(al);
		sop(al);
		
		// 存储自定义对象Person,若姓名年龄一样即为同一人
		ArrayList alp = new ArrayList();
		alp.add(new Person("lucy", 22));
		alp.add(new Person("mike", 23));
		alp.add(new Person("lili", 25));
		alp.add(new Person("jack", 25));
		alp.add(new Person("lili", 25));
		sop(alp.toString());
		alp = removeRepeatElements(alp);
		sop(alp);
	} 
	
	// 定义一个方法,移除集合中重复的元素
	public static ArrayList removeRepeatElements(ArrayList al)
	{
		ArrayList tmp = new ArrayList();
		
		for (Iterator it = al.iterator();it.hasNext();)
		{
			Object obj = it.next();
			if (!tmp.contains(obj))
			{
				tmp.add(obj);
			}
		}
		return tmp;
	}
}
注意:ArrayList判断元素是否相同使用的是equals方法
比如contains中就是判断依赖于equals方法
或者remove方法都是依赖于equals方法
尤其在存储自定义对象是,该对象一定要覆盖equals方法
建立对象自身特点的判断依据,equals就是用于比较对象内容的


练习:对字符串长度进行排序
思路:
  • 对字符串对象进行排序是很简单的。因为字符串对象本身就具备着自然顺序(字典顺序),因为它实现了Comparable接口。覆盖了compareTo方法。
  • 要求是对字符串进行长度的排序。发现字符串具备的自然顺序不是所需要的。这时就只能使用比较器的方式。
  • 需要定义个比较器。
演示代码如下:
package com.itheima.collection;
import java.util.Comparator;

public class ComparatorByLen implements Comparator
{
	public int compare(Object obj1, Object obj2)
	{
		String s1 = (String) obj1;
		String s2 = (String) obj2;
		
		int tmp = s1.length() - s2.length();
		return tmp==0 ? s1.compareTo(s1):tmp;
	}
}
package com.itheima.collection;
import com.itheima.collection.ComparatorByLen;
import java.util.TreeSet;

public class TreeSetTest
{
	public static void main(String[] args)
	{
		sop("hello,word!");
		/**
		 * 对字符串长度排序:使用比较器
		 * 
		 */
		TreeSet ts = new TreeSet(new ComparatorByLen());
		ts.add("ajagodg");
		ts.add("adgge");
		ts.add("agod90agsdg");
		ts.add("cmkadofoa");
		sop(ts);
	}

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

总结记忆:
  • 集合的技巧掌握: 明确具体集合对象名称的后缀: 
  • 如果后缀是List,都所属于List体系。通常都是非同步的。 
  • 如果后缀是Set,都属于Set体系,通常也是非同步的。 
  • 这些体系中的其他子类对象,后缀不是所属接口名的,一般都是同步的。比如Vector. 
  • 这在常用子类对象中通用。 
  • 明确数据结构: 对于jdk1.2版本的子类对象。 后缀名是所属的体系。 
  • 前缀名是就是数据结构的名称。 比如: ArrayList: 
  • 看到Array,就要明确是数组结构。查询快。 
  • LinkedList:看到Link,就要明确链表结构,就要想到 add get remove 
  • 和first last结合的方法.增删快。

综合示例演练:
  • 想要按照字符串的长度排序。
  • 说明字符串对象所具备的自然顺序不是所需要的。
  • 只好使用另一种对象比较的方式。就是比较器。 
  • 在排序的时候传入一个指定的比较器进来。 按照指定的方式进行比较排序
package cn.itcast.api.p2.comparator;

import java.util.Comparator;

public class ComparatorByStringLen implements Comparator<String> {
	public int compare(String o1, String o2) {
		
		int temp = o1.length() - o2.length();
		return temp==0?o1.compareTo(o2):temp;
	}

}
package cn.itcast.test;

import java.util.Comparator;

import cn.itcast.api.p2.comparator.ComparatorByStringLen;

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

		String[] arr = {"abcd","zz","hahaah","xixix","qq","mm","abcd","hahaah"};
		sortStringArray2(arr,new ComparatorByStringLen());
		String str = toString(arr);
		System.out.println(str);
	}

	public static void sortStringArray2(String[] arr,Comparator<String> comp){
		
		for (int i = 0; i < arr.length-1; i++) {
			for (int j = i+1; j < arr.length; j++) {
				if(comp.compare(arr[i], arr[j])>0){
					swap(arr,i,j);
				}
			}
		}
	}

	private static String toString(String[] arr) {
		
		StringBuilder sb = new StringBuilder();
		
		sb.append("[");
		for (int i = 0; i < arr.length; i++) {
			if(i!=arr.length-1)
				sb.append(arr[i]+", ");
			else
				sb.append(arr[i]+"]");
		}
		return sb.toString();
	}
	public static void sortStringArray(String[] arr){
		
		for (int i = 0; i < arr.length-1; i++) {
			for (int j = i+1; j < arr.length; j++) {
				if(arr[i].compareTo(arr[j])>0){
					swap(arr,i,j);
				}
			}
		}
	}
	private static void swap(String[] arr, int i, int j) {
		String temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值