Java10-集合

集合

集合知识点
  10.1 List接口
  10.2 Map接口
  10.3 Set接口
  10.4 泛型
  10.5 Iterator接口

  数组可以存储多个数据,但数组是定长的,不会自动扩充。如果想要对定长的数据操作,可以使用数组。如果想要对不定长的数据操作,可以使用集合。
  合理利用好集合的有序性(sort)和稳定性(order),避免集合的无序性(unsort)和不稳定性(unorder)带来的负面影响。说明:有序性是指遍历的结果是按某种比较规则依次排列的。稳定性指集合每次遍历的元素次序是一定的。

  List:底层数据结构为双向链表,支持快速增删。
  Vector:底层数据结构为数组,支持快速随机访问。
  Map:底层数据结构为红黑树,除了hashmap无序,其他实现结构有序,不重复。
  Set:底层数据结构为红黑树,除了hashset无序,其他结构有序,不重复。

  Java中数组与集合的比较
  数组也是容器,它是定长的,访问较快,但是数组不会自动扩充。
  数组可以包含基本数据类型或引用类型的对象,而集合中只能包含引用类型的对象。

10.1List接口


 |-> ArrayList:底层使用数组和列表实现,允许包括null在内的所有元素
 | (连续存储,查询性能高,有序存储,多线程不安全
 |
List---------->Vector:功能与ArrayList相同,是多线程安全的,保存有序数据的接口,可以保存相同数据。
 |
 |
 |->LinkedList:底层的数据结构是基于双向链表,允许包括null在内的所有元素。


  List接口是Collection的子接口,List接口用于存放有序数据,集合中的元素可以重复,也可以把同一个对象保存到集合中多次,即对象可重复。
  可以通过循环遍历或get方法,得到集合中的元素,再修改元素的属性值(set)方法。元素不可以修改,元素内部的属性值可以修改。
  例1:把同一对象保存到list中。

List list = new ArrayList();
Computer computer = new Computer("HP",5000);
Computer computer2 = new Computer("HW",5500);
list.add(computer);
list.add(computer);
list.add(computer2);
System.out.println(list.size());

  结果为:3。证明list中已经添加了三次数据。

  ArrayList和LinkedList:
  List有两种主要的集合实现类:
  ArrayList,以数组的形式保存集合中的元素,元素之间内存地址是连续的。ArrayList数据插入或删除时都需要移动数据,效率低;但查询时不需要寻址,可以快速查找。
  LinkedList,以链表结构保存集合中的元素,元素之间内存地址不连续。LinkedList数据插入或删除不需要移动数据,具有较高的修改性能;查询数据需要进行寻址操作。

  ArrayList的构造方法:List 变量名 = new ArrayList();
  LinkedList的构造方法:List 变量名 = new LinkedList();

  ArrayList与LinkedList的比较:
  存储结构:ArrayList是线性顺序存储,LinkedList对象间彼此串连起来的一个链表。
  操作性能:ArrayList适合随机查询的场合,LinkedList元素的插入和删除操作性高。
  功能:LinkedList要多一些。

  例1:新建ArrayList实现类,并添加数据。

public class ListDemo {
	public static void main(String[] args) {
		List li = new ArrayList();
		li.add("one");
		li.add("two");
		li.add(3);
		li.add(new Float(4.0F));
		li.add(new Integer(5));
		System.out.print(li+" ");
	}
}

  例2:新建LinkedList实现类,练习基本操作。

public class LinkedListDemo {
	public static void main(String[] args) {
		List li = new LinkedList();
		for(int i=0;i<=5;i++){
			li.add("a"+i);
		}
		//在li的索引为的位置添加数据
		li.add(3,"a100");
		/**
		 * LinkedList is a raw type. References to generic 
		 * type LinkedList<E> should be parameterized.
		 * LinkedList是一种原始类型。泛型类型LinkedList<E>的引用应该参数化
		 */
		((LinkedList) li).addFirst("a00");
		//移除里中索引0的元素
		li.remove(0);
		System.out.println("指定index="+li.get(4)+",firstindex="+((LinkedList) li).getFirst()
				+",lastindex="+((LinkedList)li).getLast());
		System.out.println(li);
	}
}

  Stack栈结构:
  push:压栈,存数据;
  peek:取栈顶数据不删除
  remove:移除数据
  pop:去除栈顶数据并删除

10.2Map接口


 |->HashMap:(key-value)底层使用数组实现,基于哈希表的Map接口的非同步实现,允许使用null值和null键,但不保证映射的顺序。在JDK8以后,HashMap的数组结构是数组+链表+红黑树。
 |
Map-------->Hashtable:底层使用数组实现,数组中每一项是个单链表:数组和链表的结合体
 | 哈希表的Map接口的同步实现,不允许使用null值和null键
 |
 |->ConcurrentHashMap:底层使用数组实现,允许多个修改操作并发进行,其关键在于使用了锁分离技术。与HashMap不同的是,ConcurrentHashMap使用多个子Hash表,也就是段(Segment) 。
 |
 |->LinkedHashMap:继承于HashMap,底层使用哈希表和双向链表来保存所有元素,并且它是非同步,允许使用null值和null键。


  Map集合用于保存有映射关系的数组,存储数据时是通过key value的对应关系进行保存的。但不能有null key,且不能有相同的key,如果存在相同的key,后面的数据会覆盖前面的数据。Map接口有两个实现类:HashMap和TreeMap。

  HashMap和Hashtable的区别
  HashMap允许null为key和value。Value值可以重复,key值不可以重复,线程不安全
  Hashtable不允许null为key和value,value值可以重复,key不能重复,线性安全。
  HashMap在容量不够进行resize时由于高并发可能出现死链,导致CPU飙升,在开发过程中可以使用其它数据结构或加锁来规避此风险。

  例:Map接口常用方法
public class MapTest {

	public static void main(String[] args) {
		Map m1 = new HashMap();
		Map m2 = new TreeMap();
		m1.put("one",new Integer(1));
		m1.put("two",new Integer(2));
		m2.put("A",new Integer(1));
		m2.put("B",new Integer(2));
		//int size()返回映射中键值映射对数
		System.out.println("m1size="+m1.size());
		//boolean containsKey(Object key)若此映射包含指定键的映射关系,返回true
		System.out.println("onekey="+m1.containsKey("one"));
		//boolean containsValue(Object value)
		//若此映射为指定值映射一个或多个键,返回true
		System.out.println("1value="+m2.containsValue(new Integer(1)));
		if(m1.containsKey("two")){
			//get(Object key)返回映射到指定键的值
			int i = ((Integer)m1.get("two")).intValue();
			System.out.println("i="+i);
		}
		//Map 变量名 = new HashMap(Map m)
		//构造一个映射关系与指定的Map相同的新的HashMap
		Map m3 = new HashMap(m1);
		//将映射m2中所有映射关系赋值到m3映射中
		m3.putAll(m2);
		System.out.println("m3="+m3);
	}
}

10.3Set接口


  |->HashSet:HashSet由哈希表(实际上是一个HashMap实例)支持,不保证set的迭代顺序,并允许使用null元素。(唯一无序性,保存数据时性能非常高,取数据会慢一些)。
 |
Set------->TreeSet:底层使用数组实现,自动升序排序(唯一性)。
 |
 |->LinkedHashSet:LinkedHashSet底层使用LinkedHashMap来保存所有元素,它继承与HashSet,其所有的方法操作上又与HashSet相同。


  Set接口是Collection的子接口,用来包含一组无序无重复的对象。无序:是指元素加入集合中的顺序和集合内存的顺序不同;无重复:是两个对象e1和e2,如果e1.equals(e2)返回true,则认为e1和e2重复,在set中只保留一个。
  利用Set元素唯一的特性,可以快速对一个集合进行去重操作,避免使用List的contains方法进行遍历、对比、去重操作。
  Set会调用equals方法进行判断,默认判断两个对象的引用是否相同。
  Set接口的实现类:
  HashSet:在遍历集合中元素时,不关系元素的顺序;
  TreeSet:按照升序排列遍历结合中的元素。
  示例:

public class HashSetTest {
	public static void main(String[] args) {
		Set a = new HashSet();
		a.add("hello");
		a.add("world");
		a.add(new Integer(100));
		//相同元素不会被加入
		a.add("hello");
		System.out.println(a);
	}
}

  结果为:[world, 100, hello]

10.4泛型

  泛型,又称参数化类型,能像方法一样接受不同类型的参数。在大部分情况下,一个集合只用于保存一类数据。为了避免在获取数据时进行类型检查,可以使用泛型集合,在保存数据时进行类型检查。
  使用泛型集合语法,在定义集合对象时,进行类型的声明
  例:List list = new ArrayList();
  在jdk1.7后,可以前面声明变量,后面为空
  例:List list = new ArrayList<>();
  使用泛型集合后,在获取数据时不需要类型转换,可以保障数据不会发生数据类型转换异常
  例:定义计算机类型的名称和价格。

public class GenericCollection {
	public static void main(String[] args) {
		List<Computer> list = new ArrayList<>();
		list.add(new Computer("HP",6000));
		list.add(new Computer("HW",6500));
		list.add(new Computer("DELL",5000));
		for(Computer computer:list){
			System.out.println(computer);
		}
		Computer com = list.get(0);
		Iterator<Computer> iterator = list.iterator();
		while(iterator.hasNext()){
			Computer com2 = iterator.next();
		}
	}
}

  使用泛型的好处:
  1.类型安全
  泛型的主要目标是提高java程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在更高的程度上验证类型假设。
  2.消除强制类型转换
  泛型的一个附带好处是,消除源代码中的许多强制类型转换。提高代码可读性,减少出错率。
  3.潜在的性能收益
  泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。更多类型信息用于编译器,为未来版本的JVM的优化带来可能。其中,由于泛型的实现方式,支持泛型不需要JVM或类文件更改。

10.5Iterator接口

  Iterator对象称为迭代器,用于对集合内的元素进行遍历操作。所有Collection接口的集合类都有一个iterator()方法,iterator在使用中只能单向移动。

  Iterator常用方法

方法含义
Object next()返回游标右边的元素并将游标移动到下一个位置
Boolean hasNext()判断游标右边是否有元素
Void remove()删除游标左边的元素,在执行完next后,该操作只能执行一次

  实例:

public class IteratorDemo {
	public static void main(String[] args) {
		HashSet<Integer> set = new HashSet<Integer>();
		for(int i=1;i<6;i++){
			set.add(new Integer(i));
		}
		//获得游标
		Iterator<Integer> it = set.iterator();
		//hasNext()判断右边右边是否有元素
		while(it.hasNext()){
			//next()返回游标游标的元素,并将游标移动到下一个位置
			Integer j = (Integer)it.next();
			System.out.print(j+" ");
			//it.remove();

		}
		System.out.println();
		System.out.println(set);
	}
}

  结果为:
  1 2 3 4 5
  [1, 2, 3, 4, 5]
  如果在next()后运行,it.remove();结果为:
  1 2 3 4 5
  []

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值