Java集合

目录

集合

Collection接口

List接口

ArrayList

LinkedList

挽救的子类Vector

Set接口

散列存放HashSet

LinkedHashSet

有序存放TreeSet

Map接口

Map集合遍历

HashMap

TreeMap

Collections


数组和集合区别

长度区别

  • 数组的长度固定
  • 集合的长度可变

内容不同

  • 数组存储的是同一种类型的元素
  • 集合可以存储不同类型的元素

元素的数据类型

  • 数组可以存储基本数据类型,也可以存储引用数据类型
  • 集合只能存储引用数据类型

集合

Java集合框架包含的内容

 

Collection:接口存储一组不唯一,无序的对象

List:接口存储一组不唯一,有序的对象(存储顺序和取出顺序一致)

Set:接口存储一组唯一,无序的对象(存储顺序和取出顺序不一致)

Map:接口存储一组键值对象,提供key到value的映射(key唯一,value不唯一)

Collection接口

添加方法

boolean add(E e)//添加一个元素
boolean addAll(Collection<? extends E> c)//添加一个集合元素

删除方法

void clear()//移除所有元素
boolean remove(Object o)//移除一个元素
boolean removeAll(Collection<?> c)//移除一个集合元素,只要有一个元素被移除,就返回true

判断方法

boolean isEmpty()//判断集合是否为空
boolean contains()//判断集合中是否包含指定元素
boolean containsAll()//判断集合中是否包含指定的集合元素,只有包含所有元素,才返回true

获取方法

Iterator<E> iterator()//迭代器,集合的专用遍历方式
Iterator i = 集合对象.iterator;
while(i.hasNext()){
    i.next();
}
不要多次使用next()方法,因为每次使用都是访问一个对象。
迭代器是依赖于集合存在的,遍历集合后修改元素,会发生并发修改异常。、

int size()//元素的个数
boolean retainAll(Collection<?> c)//仅保留两个集合都有的元素,A与B做交集,最终的结果保存在A中,B不变,返回值表示的是A是否发生过改变。
Object[] toArray()//把集合转换为数组

List接口

boolean add(Object o)//在列表的末尾顺序添加元素,起始索引位置从0开始
void add(int index,Object o)//在指定的索引位置添加元素。索引位置必须介于0和列表中元素个数之间。
boolean contains(Object o)//判断列表中是否存在指定元素
Object get(int index)//返回指定索引位置处的元素。取出的元素是Object类型,使用前需要进行强制类型转换。
boolean remove(Object o)//从列表中删除元素
Object remove(int index)//从列表中删除指定位置元素,起始索引位置从0开始
E set(int index,E element)//用指定元素替换列表中指定位置的元素
int size()//返回列表中的元素个数
int indexOf(Object o)//返回此列表中第一次出现的指定元素的索引,如果此列表不包含该元素,则返回-1
int lastIndexOf(Object o)//返回此列表中最后出现的指定元素的索引,如果此列表不包含该元素,则返回-1
List<E> subList(int fromIndex,int toIndex)//返回列表中指定的fromIndex(包括)和toIndex(不包括)之间的部分视图
ListIterator listIterator()//逆向遍历,但是必须先正向遍历

ArrayList

ArrayList()构造一个初始容量为10的空列表。

底层数据结构是数组,查询快,增删慢。线程不安全,效率高。

LinkedList

底层数据结构是链表,查询慢,增删快。线程不安全,效率高。

void addFirst(Object o)//在列表的首部添加元素
void addLast(Object o)//在列表的末尾添加元素
Object getFirst()//返回列表中的第一个元素
Object getLast()//返回列表中的最后一个元素
Object removeFirst()//删除并返回列白哦中的第一个元素
Object removeLast()//删除并返回列表中的最后一个元素

挽救的子类Vector

底层数据结构是数组,查询快,增删慢。线程安全,效率低。

void addElement(E obj)//添加
E elementAt(int index)//获取

Set接口

散列存放HashSet

里面不能存放重复元素,而且是采用散列的存储方式,所以是没有顺序的。

不保证set的迭代顺序,特别是他不保证该顺序恒久不变。

HashSet如何保证元素唯一性

底层数据结构是哈希表(元素是链表的数组)。

哈希表依赖于哈希值存储。

添加功能底层依赖两个方法:hashCode()和equals()。

给hashset存放对象必须实现Comparator接口

LinkedHashSet

底层数据结构由哈希表和链表组成,元素有序唯一。

由链表表示元素有序,由哈希表表示元素唯一。

有序存放TreeSet

能够对元素按照某种规则进行排序。

排序有两种方式:

自然排序(元素具备比较性):让元素所属的类实现Comparable接口,然后重写compareTo()方法。

对象类:
public class Examinee implements Comparable{//实现接口
	private int scorce;
 
	public Examinee(int scorce) {
		super();
		this.scorce = scorce;
	}
	public int getScorce() {
		return scorce;
	}
	@Override
	public String toString() {
		return this.getScorce()+"";
	}
	/**
	 * 重写的compareTo方法
	 */
	@Override
	public int compareTo(Object o) {
		if (o instanceof Examinee) {
			return ((Examinee) o).getScorce() - this.getScorce();
		}
		return 0;
	}
}
测试类:
public class TreeSetTest {
	public static void main(String[] args) {
		//TreeSet自然排序
		TreeSet ts = new TreeSet();
		
		ts.add(new Examinee(66));
		ts.add(new Examinee(93));
		ts.add(new Examinee(52));
		ts.add(new Examinee(75));
		ts.add(new Examinee(83));
		
		System.out.println(ts);//[93, 83, 75, 66, 52]
	}
}

比较器排序(集合具备比较性):新建TreeSet时使用匿名内部类重写compare方法。

对象类:
public class Examinee2 {// 不实现接口
	private int scorce;

	public Examinee2(int scorce) {
		super();
		this.scorce = scorce;
	}

	public int getScorce() {
		return scorce;
	}

	public void setScorce(int scorce) {
		this.scorce = scorce;
	}

	@Override
	public String toString() {
		return this.getScorce() + "";
	}
	/**
	 * 不在此重写compareTo方法。适用于不允许修改,无法实现Comparable接口的类
	 */
}

 

测试类:
public class TreeSetTest2 {
	public static void main(String[] args) {
		//TreeSet比较器排序
		TreeSet ts = new TreeSet(new Comparator() {
			//使用匿名内部类
			public int compare(Object o1, Object o2) {
				if (o1 instanceof Examinee2 && o2 instanceof Examinee2) {
					return ((Examinee2) o1).getScorce() - ((Examinee2) o2).getScorce();
				}
				return 0;
			}
		});
		
		ts.add(new Examinee2(66));
		ts.add(new Examinee2(93));
		ts.add(new Examinee2(52));
		ts.add(new Examinee2(75));
		ts.add(new Examinee2(83));
		
		System.out.println(ts);//[52, 66, 75, 83, 93]
	}
}

集合特点:有序和唯一

一个普通的类对象是不能TreeSet集合中加入的,如果直接加入会出现以下异常:java.lang.ClassCaseException,如果想要使用TreeSet则对象所在的类必须实现Compable接口。从TreeSet类的定义中可以发现,TreeSet里实现了sortedSet接口,此接口主要是用于排序操作的。

针对Collection集合我们到底使用哪一个?

判断唯一:

  • Y:Set
    • 判断排序:
      • Y:TreeSet
      • N:HashSet
  • N: List
    • 判断线程安全:
      • Y:Vector
      • N:ArrayList(查询)或LinkedList(增删)

Map接口

将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值。

Map接口和Collection接口的不同

Map是双列的,Collection是单列的

Map的键唯一,Collection的子体系Set是唯一的

Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效

方法

Object put(Object key,Object val)//以“键-值对”的方式进行存储
Object get(Object key)//根据键返回相关的值,如果不存在指定的键,返回null
Object remove(Object key)//删除由指定的键映射的“键-值对”
int size()//返回元素个数
Set keySet()//返回键的集合
Collection values()//返回值的集合
boolean containsKey(Object key)//如果存在由指定的键映射的“键-值对”,返回true

Map集合遍历

Java中的所有map都实现了Map接口,以下方法适用于任何map实现(HashMap,TreeMap,LinkedHashMap,Hashtable,等等)

  • 方法一:在for-each循环中使用entries来遍历

这是最常见的并且在大多数情况下也是最可取的遍历方式,在键值都需要时使用。

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());   
}

注意:for-each循环在java5中被引入,所以该方法只能应用于java5或更高的版本中。如果你遍历的是一个空的map对象,for-each循环将抛出NullPointerException,因此在遍历前你总是应该检查空引用。

  • 方法二:在for-each循环中遍历keys或values

如果只需要map中的键或者值,你可以通过keySet或values来实现遍历,而不是用entrySet。

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
//遍历map中的键
for (Integer key : map.keySet()) {
    System.out.println("Key = " + key);
}  
//遍历map中的值
for (Integer value : map.values()) {
    System.out.println("Value = " + value);  
} 

该方法比entrySet遍历在性能上稍好(快了10%),而且代码更加干净。

  • 方法三:使用Iterator遍历

使用泛型:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();  
while (entries.hasNext()) {   
    Map.Entry<Integer, Integer> entry = entries.next();   
    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());  
}  

不使用泛型:

Map map = new HashMap();  
Iterator entries = map.entrySet().iterator();  
while (entries.hasNext()) {  
    Map.Entry entry = (Map.Entry) entries.next();  
    Integer key = (Integer)entry.getKey();  
    Integer value = (Integer)entry.getValue();  
    System.out.println("Key = " + key + ", Value = " + value);  
}  

你也可以在keySet和values上应用同样的方法。

该种方式看起来冗余却有其优点所在。首先,在老版本java中这是惟一遍历map的方式。另一个好处是,你可以在遍历时调用iterator.remove()来删除entries,另两个方法则不能。根据javadoc的说明,如果在for-each遍历中尝试使用此方法,结果是不可预测的。

从性能方面看,该方法类同于for-each遍历(即方法二)的性能。

  • 方法四:通过键找值遍历(效率低)
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {    
    Integer value = map.get(key);   
    System.out.println("Key = " + key + ", Value = " + value);  
}  

作为方法一的替代,这个代码看上去更加干净;但实际上它相当慢且无效率。因为从键取值是耗时的操作(与方法一相比,在不同的Map实现中该方法慢了20%~200%)。如果你安装了FindBugs,它会做出检查并警告你关于哪些是低效率的遍历。所以尽量避免使用。

  • 总结

如果仅需要键(keys)或值(values)使用方法二。如果你使用的语言版本低于java 5,或是打算在遍历时删除entries,必须使用方法三。否则使用方法一(键值都要)。

HashMap

基于哈希表的Map接口实现,保证键的唯一性。

无序存放的,是新的操作类,key不允许重复。

Hashtable和HashMap的区别

Hashtable:线程安全,效率低,不允许null键和null值。

HashMap:线程不安全,效率高,允许null键和null值。

TreeMap

键是红黑树结构,可以保证键的排序和唯一性。

可以排序的Map集合,按集合中的key排序,key不允许重复。

Collections

是针对集合进行操作的工具类,都是静态方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值