Java集合知识点详细概括加代码解释

集合Collection (List And Set)

1.在实际开发中,需要将使用的对象存储于特定的数据结构容器中。JDK提供了这样的容器-集合(Collection)。

2.Collection 是一个接口,其子接口有:List和Set

3.List和Set的区别:List是有序可重复集(可以存储重复元素),Set是无序不可重复集(不能存储重复元素)。元素是否重复取决于元素的equals()比较结果。

集合持有对象的引用

集合中存储的都是引用类型元素,并且集合只保存每个元素的引用,而非将元素本身存入集合。基本类型数据会自动装箱为Integer类型数据。

Collection 中的常用方法

add()方法

1.Collection 定义了一个add方法用于向集合中添加新元素

		-boolean add(E e) E表示的是数据类型
该方法会将给定的元素加进集合 若添加成功则返回true,否则返回false

演示代码如下:

public void testAdd() {
 	Collection<String> c = new ArrayList<String>();
 	System.out.println(c);//[]
 	c.add("a");
 	c.add("b");
 	c.add("c");
 	System.out.println(c);//[a,b,c]
 }

contains()方法

	-boolean contains(Object o)
该方法用于判断给定的元素是否包含在集合中,若包含则返回true,否则返回false。
注意:集合判断元素是否被包含在集合中是根据equals方法,进行比较后的结果。
通常类有必要重写equals方法 来保证比较的合理性。

演示代码如下:

	public void  testContains() {
		Collection<Person> persons = new ArrayList<Person>();
		persons.add(new Person("张三",20));
		persons.add(new Person("李四",21));
		persons.add(new Person("王五",22));
		persons.add(new Person("赵六",23));
		Person p =new Person("李四",21);
		//List集合contains方法和对象的equals方法有关
		boolean flag = persons.contains(p);
		//如果Person类不重写equals方法将为false
		System.out.println(flag);//true
	}

int size(),void clear,boolean isEmpty

-int size()返回当前集合中元素的总数
-void clear() 该方法清空当前集合
-boolean isEmpty()该方法用于判断集合是否为空

演示代码如下:

	public void testSizeAndClearAndIsEmpty() {
		Collection<String> c = new HashSet<String>();
		System.out.println(c.isEmpty());//true
		c.add("Java");
		c.add("C");
		c.add("php");
		c.add("C#");
		c.add("Java");
		System.out.println(c);//无序不可重复:[C#, Java, C, php]
		System.out.println("isEmpty:"+c.isEmpty()+",size:"+c.size());//false  4
		c.clear();
		System.out.println("isEmpty:"+c.isEmpty()+",size:"+c.size());//true 0
	}

addAll()方法和containsAll()方法

	-boolean addAll(Collection<? extends E> c)
该方法需要我们传入一个集合,并将该集合中的所有元素添加到当前集合中
如果此collection 由于调用而发生更改,则返回true
	-boolean containsAll(Collection<?> c)
该方法用于判断当前集合是否包含给定集合中的所有元素
若包含则返回true

演示代码如下:

   public void testAddAllAndContainsAll() {
   	Collection <String >c1 = new ArrayList<String>();
   	c1.add("java");
   	c1.add("c");
   	c1.add("php");
   	c1.add("c#");
   	c1.add("js");
   	System.out.println(c1);//java c php c# js
   	Collection <String> c2 = new HashSet<String>();
   	c2.addAll(c1);
   	System.out.println(c2);//无序 java php c js c#
   	Collection <String>c3= new ArrayList<String>();
   	c3.add("java");
   	c3.add("c");
   	System.out.println(c1.containsAll(c3));//true
   }
   }

迭代器 Iterator

迭代器用于遍历集合元素,获取迭代器可以使用Collection定义的方法:

Iterator <E> it = 集合名.iterator();

迭代器是一个接口,集合在重写了Collection的iterator()方法时利用内部类提供了迭代器的实现。

Iterator提供了统一的遍历集合的方式,其提供了用于遍历集合的两种方法:

boolean hasNext():判断集合是否还有元素可以遍历
E next():返回迭代的下一个元素

演示代码如下:

	public void testHashNextAndNext() {
		Collection<String> c = new HashSet<String> ();
		c.add("java");
		c.add("c");
		c.add("c#");
		c.add("php");
		c.add("python");
		//获取迭代器
		Iterator<String> it = c.iterator();
		//判断是否有元素 然后遍历
		while(it.hasNext()) {
			//返回元素
			String s = it.next();
			System.out.println(s);
		}
	}

remove()方法

在使用迭代器遍历集合时,不能通过集合的remove()删除集合中的元素,否则会抛出并发更改异常。

void remove()
1.我们通常使用迭代器自身提供的remove()方法来删除通过next()方法迭代出来的元素。
2.迭代器的删除方法是在原集合中删除元素。
3.这里需要注意的是:在调用remove方法前必须通过迭代器的next方法迭代过的元素,
那么删除的就是这个元素,并且不能再次调用remove方法,除非再次调用next方法后
方可调用remove()方法

演示代码如下:

	public void testRemove() {
		Collection<String> c = new HashSet<String>();
		c.add("java");
		c.add("C");
		c.add("C#");
		c.add("PHP");
		c.add("python");
		System.out.println(c);
		Iterator<String> it = c.iterator();
		while(it.hasNext()) {
			String s = it.next();
			if(s.indexOf("C")!= -1) {  //不等于-1 是找到 等于-1没有找到
				it.remove();//删除包含字母C的元素
			}
		}
		System.out.println(c);//python java php 把包含C字母的元素全部删除
	}

增强for循环

java5.0版本之后推出了一个新特性,增强for循环,也称为新循环,该循环不同于传统的循环工作,只用于遍历数组和集合。

语法:

for (元素类型 e:集合或者数组){
	循环体;
}
新循环并非新语法,而是在编译过程中,编译器会将新循环转化为迭代器模式
所以可以说新循环的本质是迭代器

演示代码如下:

		public void testFor() {
			Collection<String> c = new HashSet<String>();
			c.add("java");
			c.add("c");
			c.add("php");
			c.add("c#");
			c.add("python");
			for (String string : c) {
				System.out.println(string.toUpperCase()+" ");
				//C# PYTHON JAVA C PHP
			}
	}

泛型机制

1.泛型机制是JavaSE 5.0引入的特性,泛型的本质是参数化类型,在类 接口 和方法的定义过程中,所操作的数据类型被传入的参数指定。

2.Java泛型机制广泛的应用在集合框架中,所有的集合类型都带有泛型参数,这样在创建集合时可以指定放入集合中元素的类型,java编译器可以据此类型进行检查,这样就可以减少代码在运行时出现的错误可能性。

3.ArrayList类的定义中,中的E为泛型参数,在创建对象时可以将类型作为参数传递,此时类定义所有的E将被替换成传入的参数。

演示代码如下:

	public void testE() {
		ArrayList<String> list = new ArrayList<String>();
		list.add("One");//只能添加String类型的数据
	}

集合操作-线性表

List

1.List接口是Collection的子接口,用于定义线性表数据结构,可以将List理解为存放对象的数组,只不过元素个数可以动态的增加或者减少。

2.List接口的两个常见实现类为ArrayList和LinkedList分别用动态数组和链表的方式实现了List接口

3.可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定的差别。ArrayList更适合于随机访问,LinkedList更适合插入和删除。

常用方法

List除了继承Collection定义的方法外,还根据其线性表的数据结构定义了一系列的方法,其中最常用的就是基于下标的get和set方法。

E get(int index) 获取集合中指定下标对应的元素,下标从0开始
E set(int index,E element)将指定的元素存入指定的位置,并将原位置元素返回

演示代码如下:

	public void testGetAndSet() {
		List<String> list = new ArrayList <String>();
		list.add("java");
		list.add("c++");
		list.add("php");
		list.add("python");
		list.add("c#");
		//get方法遍历List
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i).toUpperCase());
			//JAVA C++ PHP PYTHON C#
		}
		String value = list.set(1, "hadoop");
		System.out.println(value);//c++
		System.out.println(list);//java hadoop php python c#
		//先拿到hadoop 将 hadoop插入索引3的位置 把python 返回,然后再把python插入索引1的位置
		list.set(1, list.set(3, list.get(1)));
		System.out.println(list);
		//java python php hadoop c#
	}
根据下标的操作进行插入和删除
void add(int index,E element)将给定的元素插入到指定位置,原位置以及后续
元素都顺序向后移动
E remove(int index):删除给定位置的元素,并将被删除的元素返回

演示代码如下:

	public void testInsertAndRemove() {
		List<String> list = new ArrayList<String>();
		list.add("java");
		list.add("c++");
		System.out.println(list);//java c++
		
		list.add(1,"cpp");
		System.out.println(list);//java cpp c++
		
		String a = list.remove(2);
		System.out.println(list+".."+a);//java cpp...c++
	}
获取子List(sublist)
注意sublist获取的List与原List占用相同存储空间,对子List的操作会影响原List
List<E>sublist(int fromIndex,int toIndex) fromIndex和toIndex是截取子
List的首尾下标,前包后不包。

演示代码如下:

	public void testSubList() {
		List<Integer> list = new ArrayList<Integer>();
		for (int i = 0; i < 10; i++) {
			list.add(i);
		}
		System.out.println(list);//0-9
		
		List<Integer> sublist = list.subList(3, 8);//3 4 5 6 7
		//subList获得的List和源List占有相同的资源
		for (int i = 0; i < sublist.size(); i++) {
			sublist.set(i, sublist.get(i)*10);
		}
		System.out.println(sublist);//30 40 50 60 70
		//用的是同一块 存储空间 对子List操作会影响原List
		System.out.println(list);// 0 1 2 30 40 50 60 70 8 9
		//注意clear只能删除连续元素
		list.subList(3, 8).clear();
		System.out.println(list);// 0 1 2  8 9
	}
List与数组之间的转化

1.List的toArray方法用于将集合转化为数组,但实际上该方法是在collection的接口中定义的,所以所有的集合都具备这个功能。

Object[] toArray()
<T> T[] toArray(T[] a)
其中第二个方法是比较常用的,我们可以传入一个指定的类型的数组,该数组元素类型
一致。返回值是转换后的数组,该数组会保留集合中的所有元素

演示代码如下:

	public void testToArray() {
		List<String> list = new ArrayList<String>();
		list.add("a");
		list.add("b");
		list.add("c");
		String [] strArr = list.toArray(new String[] {});
		System.out.println(Arrays.toString(strArr));//[a,b,c]
	}

2.Arrays数组类中提供了一个静态方法asList 使用该方法我们可以将一个数组转化为对应的List集合

static <T> List<T> asList<T...a>
返回的List集合元素类型由传入的数组的元素类型决定
返回的集合我们不能对其增删元素,否则会抛出异常,并且对集合的元素进行修改
会影响数组对应的元素。

演示代码如下:

	public void testArrayToList() {
		String [] strArr = {"a","b","c"};
		List<String> list = Arrays.asList(strArr);
		System.out.println(list);
		//list.add("d");//抛出异常
		//System.out.println(list);
		List<String> list1 = new ArrayList<String>();
		list1.addAll(Arrays.asList(strArr));
		list1.add("d");
		System.out.println(list1);
		/*
		 * 数组转化为List是不能增删的 如果需要增删 可以利用空集合调用addAll方法将转换后的集合全部添加 新集合
		 * 	就可以进行操作了。
		 */
	}
List排序

1.Collections是集合的工具类,它提供了很多便于我们操作集合的方法,其中就有用于集合排序的sort方法

该方法定义为:
-void sort(List<T> list)
该方法的作用是对给定的集合元素进行自然排序

演示代码如下:

		public void testSort() {
		List<Integer> list = new ArrayList<Integer>();
		Random r = new Random();
		for (int i = 0; i <10;i++) {
			list.add(r.nextInt(100));
		}
		System.out.println(list);//[7, 77, 94, 15, 6, 83, 35, 30, 24, 49]
		Collections.sort(list);//从小到大排序
		System.out.println(list);//[6, 7, 15, 24, 30, 35, 49, 77, 83, 94]
	}
Comparable

Collections的sort方法是对集合的自然排序,那么两个元素对象之间就一定要分大小,这个大小之分是如何判断的呢?实际上在使用Collections的sort排序的集合元素都必须是Comparable接口的实现类。

该接口表示子类是可以比较的,因为实现接口必须重写抽象方法

int compareTo(T t);
该方法用于使当前对象与给定对象进行比较
若当前对象大于给定对象 返回值为大于0的整数
若当前对象小于给定对象	返回值为小于0的整数
若两个对象相等        则返回0

演示代码如下:

	public void testComparable() {
		/*
		 * Cell实现了Comparable 接口
		 * compareTo 方法逻辑为 按照x值大小进行排序
		 */
		List<Cell> cells = new ArrayList<Cell>();
		cells.add(new Cell(2,3));
		cells.add(new Cell(5,1));
		cells.add(new Cell(3,2));
		Collections.sort(cells);
		System.out.println(cells);
		2,3   3,2   5,1
	}
Comparator

1.一旦Java类实现了Comparable接口,其比较逻辑就已经确定,如果希望在排序的操作中,临时指定比较规则,可以采用Comparator接口回调的方式
2.Comparator 接口要求实现类必须重写其定义的方法:

int compare(T o1,T o2)
若o1>o2 方法的返回值应大于0
若o1<o2 方法的返回值应小于0
若o1=o2则返回0

演示代码如下:

		public void testComparator() {
		List<Cell> cells = new ArrayList<Cell>();
		cells.add(new Cell(2,3));
		cells.add(new Cell(5,1));
		cells.add(new Cell(3,2));
		//临时按照y排序 this.y-o.y
		Collections.sort(cells, new Comparator<Cell>() {
			@Override
			public int compare(Cell o1, Cell o2) {
				// TODO Auto-generated method stub
				return o1.y-o2.y;
			}
		});
		System.out.println(cells);//5,1 3,2 2,3
		//临时回调
		Collections.sort(cells);
		System.out.println(cells);//2,3 3,2 5,1
	}
比较总结

1.对于集合比较实用Collection.sort()

2.对于集合中的对象比较,需要指定比较逻辑,需要实现Comparable接口并重写compareTo方法自定义逻辑

3.对于需要临时改变比较规则,需要使用Collections.sort(List,Comparator)采用回调方式重写Comparator接口的compare方法自定义逻辑。

Queue和Deque

Queue

1.队列Queue是常用的数据结构,可以将队列看成特殊的线性表,队列限制了对线性表的访问方式,只能从线性表的一端添加元素(offer)从另一端取出(poll)元素

2.队列遵循先进先出的原则

3.JDK提供了Queue接口,同时使得LinkedList实现了该接口,选择LinkedList实现Queue接口的原因在于Queue经常要进行添加和删除的操作,而LinkedList在这方面效率比较高。

4.Queue接口主要方法如下:

boolean offer(E e):将一个对象添加至队尾,如果添加成功则返回true
E poll():从队首删除并返回一个元素
E peek():返回队首元素但是不删除

演示如下代码:

	public void testQueue() {
		Queue<String> queue = new LinkedList<String>();
		queue.add("a");
		queue.offer("b");
		queue.offer("c");
		System.out.println(queue);//a b c
		String str = queue.peek();
		System.out.println(str);//a
		String str1 = queue.poll();
		System.out.println(str1);//a
		System.out.println(queue);//b c
		
		while(!queue.isEmpty()) {
			str = queue.poll();
			//遍历只能用删除队首 poll方法 删除后队首元素会变为第二个元素 而peek不会改变队首元素
			System.out.println(str+" ");//b c
		}
	}

Deque

1.Deque是Queue的子接口,定义了所谓的 双向队列。即从队列的两端分别可以入队(offer)和出队(poll)。LinkedList实现了该接口

2.如果将Deque限制为只能从一端入队和出队,则可实现 栈 Stack 的数据接口
入栈称为push 出栈称为pop

3.栈遵循先进后出的原则

	public void testStack() {
		Deque<String> stack = new LinkedList<String>();
		stack.push("a");
		stack.push("b");
		stack.push("c");
		System.out.println(stack);//c b a
		String s = stack.peek();
		System.out.println(s);//c
		while(!stack.isEmpty()) {
			 s = stack.pop();
			 System.out.println(s+" ");// c  b  a
		}
		System.out.println(stack);//[]
	}
	}

Map接口

1.Map接口定义的集合又称之为查找表,用于存储所谓的"Key-Value"映射对。Key可以看成是Value的索引,作为key的对象在集合中不可以重复。

2.根据内部数据结构不同,Map接口有多种实现类,其中常用的有内部为hash表实现的HashMap和内部为排序二叉树实现的TreeMap

put()方法

1.Map接口中定义了向Map中存放元素的put方法

V put(K key,V value)

2.将key-value对存入Map,如果在集合中已经包含了该Key,则操作将替换该key所对应的value,返回值为该key原来所对应的value,如果没有包含该Key返回null。
演示代码如下:

	//创建成员变量
	Map<String,Person> persons = new HashMap<String,Person>();
	@Before //表示在每执行一次test就执行一次before
	public void testPut() {
		persons.put("张三", new Person("张三",80));
		persons.put("闫伟", new Person("闫伟",81));
		//System.out.println(persons);
	}

3.Map接口中定义了从Map中获取元素的get方法

V get(Object key)返回参数key所对应的value对象,如果不存在则返回null

演示代码如下:

	@Test
	public void testGet() {
		Person  p = persons.get("张三");
		System.out.println(p);//Person [name=张三, age=80]
	}

containsKey()方法

Map接口中定义了判断某个key是否在Map中存在

boolean containsKey(Object key)
若Map中包含给定的key则返回true

演示代码如下:

	@Test
	public void testContainsKey() {
		System.out.println(persons.containsKey("闫伟"));//true
	}

hashCode方法

1.从hashMap的原理中我们可以看到,key的hashCode()方法的返回值对HashMap存储元素时会起着
非常重要的作用,而hashCode()方法实际上是在Object中定义的

2.对于重写了equals方法的对象,一般要妥善的重写继承自Object类的hashCode方法
(Object提供的hashCode方法 将返回该对象所在内存地址的整数形式)

3.重写hashCode方法应注意两点:

 		-与equals方法的一致性,即equals比较返回true的两个对象其hashCode方法返回值应该相同
 		-hashCode返回的数值应符合hash算法的要求,如果有很多对象的hashCode返回值都相同 则会大大降低
  			hash表的效率,一般情况下使用IDE eclipse提供的工具自动生成hashCode方法

装载因子及hashMap优化

1.Capacity:容量,hash表里bucket的数量 也就是散列数组大小

2.Inintal capacity:初始容量,创建hash表时,初始bucket的数量,默认构建容量是16
也可以使用特定的容量

3.Size:大小,当前散列表中存储数据的数量

4.Load factor:加载因子 默认值为0.75,当向散列表增加数据时 如果size/capacity的值大于factor则扩容
并且重新散列(rehash)

5.性能优化:加载因子较小时 散列查找性能会提高,同时也浪费了散列桶的容量。0.75是性能和空间相对平衡结果
在创建散列表时 指定合理的容量,减少rehash提高性能

Map遍历

1.Map提供了三种遍历方式

遍历所有的key
遍历所有的key-value对
遍历所有的value---不常用

2.遍历所有key的方法

Set<K> keySet()
该方法返回当前Map中所有Key存入一个Set集合

演示代码如下:

	@Test
	public void testKeySet() {
		Set<String> keyset = persons.keySet();
		System.out.println(keyset);//[张三, 闫伟]
		for (String string : keyset) {
			System.out.println("key:"+string);
			/*
			 * key:张三
			 * key:闫伟
			 */
		}
	}

entrySet()方法 遍历所有键值对

Set<Entry<k,v>> entrySet()
该方法将当前Map中的每一组key-value对封装为一个Entry对象并存入一个
Set集合返回

演示代码如下:

	public void testEntrySet() {
		Set<Entry<String,Person>> entrySet = persons.entrySet();
		//[张三=Person [name=张三, age=80], 闫伟=Person [name=闫伟, age=81]]
		System.out.println(entrySet);
		
		for (Entry<String, Person> entry : entrySet) {
			System.out.println(entry.getKey()+":"+entry.getValue());
			/*
			 * 张三:Person [name=张三, age=80]
			 * 闫伟:Person [name=闫伟, age=81]
			 */
		}
	}

有序的Map

1.使用Map接口的哈希表和链表实现,具有可预知迭代顺序,此实现与HashMap的不同之处在于:
LinkedHashMap维护着一个双向循环链表,此链表定义了迭代顺序,该迭代顺序通常就是存放元素的顺序。

2.需要注意,如果在Map中重新存入已有Key,那么key位置不会发生改变,改变的是value值。

演示代码如下:

	@Test
	public void testLinkedHashMap() {
		LinkedHashMap<String,Person> map = new LinkedHashMap<String,Person>();
		map.put("李志豪", new Person("李志豪",99));
		map.put("李四", new Person("李四",18));
		System.out.println(map);
		//{李志豪=Person [name=李志豪, age=99], 李四=Person [name=李四, age=18]}
		map.put("李四", new Person("李四",66));
		System.out.println(map);
		//{李志豪=Person [name=李志豪, age=99], 李四=Person [name=李四, age=66]}
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值