Java核心语法——集合(单列集合Collection、双列集合Map)

集合

概述

前话

对象类型的数组,都单独指向一个对象。

	Pserson p = new Person[2];
	p[0] = new Person("张三"17);
	p[1] = new Person("李四"18);
	for(int i = 0;i < p.length ; i++){
		System.out.println(p[i]);//默认调用toString()
	}

对象类型的数组每次声明时,都要固定对象个数,不便于扩容。并且要实现的每一个功能都需要手动编写创建。集合就应运而生。

注意:
1)数组:可以存储基本数据类型、引用类型
2)集合:只能存储引用类型,因为底层使用的Object数组来装数据,而基本数据类型不包含在Object中,但是基本数据类型对应的包装类对象可以存储在Object中,所以,也根据自动装箱、拆箱可以直接存储基本数据类型。

【罗列】

单列集合:

	定义:每一个元素对应一个数据
	
	罗列:
	Collection								单列集合的顶层接口
		List								可不唯一、有序的子接口
			*ArrayList						顺序存储,查询修改快,通过数组实现
			LinkedList						链式存储,增加删除快,节点实现
			
		Set									唯一、无序的子接口
			*HashSet						哈希存储,保证元素唯一
				LinkedHashSet				唯一、有序
		
		ps:节点——》一个节点中,存储一个数据,和下一个数据的节点的地址

双列集合:

	定义:每一个元素,存储一对数据
	选择:表示对应关系、键复杂推荐使用Map
	
	罗列:
	Map										唯一、双列集合的顶层接口
		*HashMap							哈希表存储,键值对唯一
			LinkedHashMap					唯一、有序

Collection

【特点】

1、单列集合的顶层接口,定义的是所有单列集合共有的功能
2、接口不可实例化,要调用接口的方法时,随意找个实现类即可(多态)
eg:Collection c = new ArrayList()

常用方法

注意:这是Collection单列顶层接口中定义的所以单列共有的方法。所以子类中都可以直接使用

数据与集合

add(Object obj)
remove(obj)
clear()
isEmpty()
contains(obj)——》判断集合中是否包含obj
size()

注意:
    remove()删除时,需要比较两个对象的数据是否相同,如果两个对象中的数据相同,就删除。
    例如:通过Person对象中的equals()对比,自定义类需要重写equals()

例如:

		Collection c = new ArrayList();
		c.add(123);
		c.add("zhangsan");
		c.add(new Person("李四",23));
		System.out.println(c);
		
		//如果两个对象中的数据相同,就删除
		//通过Person对象中的equals()对比,自定义类需要重写equals()
		c.remove(new Person("李四",23));
		System.out.println(c);
集合与集合

addAll(Collection c)——》将参数c完全复制给调用者

removeAll(Collection c)——》在调用者中,完全删除参数c

containsAll(c )——》判断是否是子集。判断c是否是调用者的子集

retainAll(c )——》求交集,并赋值给调用者

注意:判断是否时子集时不看重复出现的那一部分,比如{1,1}是{1,2}的子集。list集合没有要求元素唯一

		Collection c1 = new ArrayList();
		Collection c2 = new ArrayList();
		c1.add("123");
		c1.add("456");
		System.out.println(c1);//[123, 456]
		
		c2.addAll(c1);
		c2.add("123");
		System.out.println(c2);//[123, 456, 123]
		System.out.println(c1.containsAll(c2));//ture。c2是c1的子集
迭代器

通过迭代器(接口)定义的功能iterator()获取每一个实现类对象,因为有很多对象,而我们没必要去区分每一个对象,所以向上转型为迭代器接口,即可。Iterator it = new ArrayList().iterator();

迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址,简单地说,迭代器是一种检查容器内元素并遍历元素的可带泛型的数据类型的对象。

迭代器,也可以称作为游标,通俗点来说,是为了实现一个一个数(三声)数(四声)的目的。

Iterator接口中的方法

iterator()迭代器实现类对象,可以使用Iterator接口中的方法

hasNext()——》判断是否还有下一个元素
next()——》获取下一个元素
remove()——》删除迭代器对象正在迭代的对象
【Collection遍历】

一、集合转数组
Object[] toArray()——》将调用者集合,转成Object类型的数组

二、迭代器
Iterator it = new ArrayList().iterator();

三、 直接使用增强for循环

	Collection<Object> c = new ArrayList<Object>();
	c.add(123);
	c.add("abc");
	c.add(new Person1("李四",19));
	for (Object object : c) {
		System.out.println(object);
	}

List

概述

List是Collection的子接口

特点
1)有序
2)可重复
3)有索引

特有方法

add(int index,Object obj)
remove(int index)
set(int index,Object obj)
get(int index)

List的遍历

可以使用Collection中的两种遍历方式、其实直接使用增强for循环也可以

特有的遍历方式
通过size()获取索引范围,通过get()获取每一个索引上的元素

public class demo_List的遍历 {

	public static void main(String[] args) {
		List<Object> list = new ArrayList<Object>();
		list.add(123);
		list.add("abc");
		list.add(new Person1("张三",18));
		
		test_第四种遍历_list特有的get方法(list);	
	}

	
	private static void test_第四种遍历_list特有的get方法(List<Object> list) {
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
	}

	private static void test_第三种遍历_迭代器(List<Object> list) {
		Iterator<Object> it = list.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}

	private static void test_第二种遍历_转数组(List list) {
		Object[] obj = list.toArray();
		//增强for循环
		for (Object object : obj) {
			System.out.println(object);
		}
		//普通for循环
		for (int i = 0; i < obj.length; i++) {
			System.out.println(obj[i]);
		}
	}
	
	private static void test_第一种遍历_直接使用增强for循环(List<Object> list) {
		for (Object object : list) {
			System.out.println(object.toString());
		}
	}

}

class Person1{
	private String name;
	private int age;
	public Person1() {
		super();
	}
	public Person1(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	
}

并发修改异常

ConcurrentModificationException
Concurrent:并发、Modification:修改

1、出现的原因是什么?
在使用迭代器对象遍历集合的同时,对集合进行增加元素的操作

2、如何避免并发修改异常?
避免迭代器与集合交叉遍历和增删

1)迭代器进行遍历和增删
	普通的迭代器没有增加元素的功能,需要使用List集合特有的迭代器ListIterator子接口,使用listiterator()方法获取迭代器对象
		List<Object> list = new ArrayList<Object>();
		list.add(123);
		list.add("abc");
		list.add(new Person1("张三",18));
		
		ListIterator<Object> it = list.listIterator();
		while (it.hasNext()) {
			Object object = (Object) it.next();
			if("abc".equals(object)) {
				it.add(456);
				//it.remove();
			}
			System.out.println(object);
		}
		//添加删除之后再次遍历
		for (Object object : list) {
			System.out.println(object);
		}
2)集合遍历和增删
遍历:对于List集合进行遍历就使用list集合特有的get方法进行遍历
添加:使用集合的add进行添加(使用list特有的,或者Collection共有的都可以)
		List<Object> list = new ArrayList<Object>();
		list.add(123);
		list.add("abc");
		list.add(new Person1("张三",18));
		
		for (int i = 0; i < list.size(); i++) {
			if(i == 1)
				list.add("def");
			System.out.println(list.get(i));
		}

List的两个实现类

List只是一个接口,根据底层实现方式的不同,需要具有不同的实现类
ArrayList:数组实现,顺序存储
LinkedList:节点实现,链式存储

ArrayList

List的一个实现类

存储方式
1)顺序存储
2)连续存储,每个元素都是挨在一起存储的,空间是连续的

特点
1)查询快:通过索引计算查询,可以很快定位
2)增删慢:每次增删都要改变它后面所有元素的索引。增加加一、删除减一
在这里插入图片描述

LinkedList

List接口的另一实现类

存储方式
1)节点实现,链式存储
2)不是连续存储的。每一个节点都有一个地址,除了存储自己的元素,还有下一个节点的地址

特点
1)查询慢:需要计算,查找元素的位置(比较乱找得慢)
2)增删快:改变上一个节点和自己这个节点的指向即可(比较乱,随意增加删除,对其他节点影响较小)
在这里插入图片描述

LinkedList特有的方法

因为是节点实现,需要长期存储头部节点、尾部节点的地址,所有提供了许多操作头部尾部的方法

addFirst(Object obj)——》在头部添加元素
addLast(Object obj)——》在尾部添加元素
removeFirst()
removeLast()
getFirst()
getLast()

【泛型】

概述

广泛的类型,包含Object类型。(基本类型在包装类,包装类也包含于Object)
相当于一个变量,可以是任何的类型(使用时,指定其类型即可),基本类型需要使用对应的包装类型

泛型类的定义

		class 类名 <随便一个符号,一般大写字母>{
			……
		}
		一般是:T	E	K	V	Q	W

泛型的确定:
一般在创建对象时确定泛型,所以静态方法不能使用类上声明的泛型(静态方法在创建对象之前就可以调用),需要定义为泛型方法

public class demo_泛型 {

	public static void main(String[] args) {
		SetStack<Integer> sl = new SetStack<Integer>();
		sl.push(123);
		sl.push(456);
		sl.push(789);
		
		while( !sl.isEmpty()) {
			System.out.println(sl.pop());//789,456,123
		}
	}

}

class SetStack <E> {
	private LinkedList<E> ldl = new LinkedList<E>();
	//给栈头添加元素,压栈push
	public void push(E e) {
		ldl.addFirst(e);
	}
	//删除栈头,弹栈pop
	public E pop() {
		return ldl.removeFirst();
	}
	
	public boolean isEmpty() {
		return ldl.isEmpty();
	}
}

泛型方法的定义

权限修饰符 <泛型> 返回值类型 命名(参数列表){
	……
}
public class demo_泛型_方法 {

	public static void main(String[] args) {
		Integer[] in = {1,2,3,6,5};
		System.out.println(Arrays.toString(in));
		change(in,0,4);
		System.out.println(Arrays.toString(in));
		
		String[] str = {"abc", "*","123"};
		System.out.println(Arrays.toString(str));
		change(str,1,2);
		System.out.println(Arrays.toString(str));
	}
	
	//定义一个泛型方法,功能是交换数组指定位置上的两个元素
	public static <T> void change(T[] t,int a,int b) {
		T temp = t[a];
		t[a] = t[b];
		t[b] = temp;
	}

}
【泛型方法的特点】

1)非静态方法:如果要使用泛型,可以在方法上声明,也可以使用类上声明的泛型
2)静态方法:只能声明方法泛型,因为类需要在创建之后,才能确定泛型,而静态方法不要创建就可以使用

泛型通配符

?、? extends E、? super E

①?:对当前泛型没有要求,可以是与E没有任何关系(对实际参数没有任何要求)

Collection<E> removeAll( Collection<?> c)

②? extends E:对当前泛型有要求,要求不能超过E。(当前泛型是子类,E是父类)

Collection<E> addAll( Collection<? extends E> c)
比如:String、StringBuilder是字符序列CharSequence接口的实现类。如果E是CharSequence,那么的就可以addAll()   String、StringBuilder

③? super E:对泛型有要求,要求不止T,包含T。(当前泛型是父类,E是子类)

Arrays.sort(E[] e,Comparator<? super E> c)

Set

说明:Collection下的一个无序子接口
特点:
1)无序         2)无索引         3)元素不可重复

	Set<Integer> se = new HashSet<Integer>();
	se.add(123);
	se.add(123);
	se.add(456);
	se.add(789);
	se.add(4567);
	System.out.println(se.toString());//[789, 4567, 456, 123]

【Set遍历(四种)】

没有特有的方法,仍然使用Collection的遍历方式
一、无泛型toArray()

package com.first.demos;

import java.util.HashSet;
import java.util.Set;

public class demo_遍历_无泛型toArray {

	public static void main(String[] args) {
		Set<Integer> se = new HashSet<Integer>();
		se.add(123);
		se.add(456);
		se.add(789);
		se.add(4567);
		
		Object[] obj = se.toArray();
		
		for (int i = 0; i < obj.length; i++) {
			Integer it = (Integer)(obj[i]);
			System.out.println(it);
		}
	}

}

二、有泛型toArray()。
传入的是什么类型的集合,转数组后返回的就是什么类型的数组

package com.first.demos;

import java.util.HashSet;
import java.util.Set;

public class demo_遍历_带泛型的toArray {
	//带泛型的toArray()。传入的是什么类型的集合,转数组后返回的就是什么类型的数组
	public static void main(String[] args) {
		Set<Integer> se = new HashSet<Integer>();
		se.add(123);
		se.add(456);
		se.add(789);
		se.add(4567);
		//如果创建的大小与实际所需大小不等
		//1.所需小于创建,前几个装实际数据,后面没使用的装null
		//2.所需等于创建,直接使用创建的
		//3.所需大于创建,不够装,重新创建一个集合(不在使用自己创建的那个集合,全为null)
		Integer[] it1 = new Integer[3];
		Integer[] it2 = se.toArray(it1);
		
//		System.out.println(it1 + "\t" + Arrays.toString(it1));
//		System.out.println(it2 + "\t" + Arrays.toString(it2));
		
		for (int i = 0; i < it2.length; i++) {
			System.out.println(it2[i]);
		}
		
	}

}

三、迭代器

package com.first.demos;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class demo_遍历_迭代器 {

	public static void main(String[] args) {
		Set<Integer> se = new HashSet<Integer>();
		se.add(123);
		se.add(456);
		se.add(789);
		se.add(4567);
		
		Iterator<Integer> it = se.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}

}

四、增强for循环

格式:
	for(  元素的数据类型  命名 : 要遍历的集合 ){
			直接使用元素的名称进行操作
			……
	}

快捷键:fore + alt + /

package com.first.demos;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

public class demo_遍历_增强for循环 {

	public static void main(String[] args) {
		Set<Integer> se = new HashSet<Integer>();
		se.add(123);
		se.add(456);
		se.add(789);
		se.add(4567);
		//容器元素类型 元素命名 : 需要遍历的容器
		for (int i  : se) {
			//直接使用元素名操作
			System.out.println(i);
		}
		System.out.println();
		
		//底层就是迭代器
			//1.不能增删元素(并发修改)
			//2.不能使用迭代器增删元素(拿不到迭代器)、List集合有特有的迭代器
			//3.不能修改元素(找不到位置)
			//4.但是可以修改集合中记录的指向对象的内容(拿不到对应hash表的索引,但是可以找到某个对象的地址,从而找到它存储的数据)
			ArrayList<StringBuilder> al = new ArrayList<>();
			al.add(new StringBuilder("123"));
			al.add(new StringBuilder("abc"));
			
			for (StringBuilder sb : al) {
				//修改集合中记录的指向对象的内容
				sb.replace(0, sb.length() , "***");//[***, ***]
			}
			System.out.println(al.toString());
	}

}

Set实现类

HashSet实现类
描述

保证数据唯一性,且元素之间位置不会发生变化
but:
    存储自定义类型Person时,每次都会new一个Person对象,那么就算对象中的数据相同,但是地址不同那么它也是不相同的,不会保证数据唯一性。就需要重写equals(),但是不会调用,也没用。因为没有重写hashCode()。如果需要保证数据唯一性,需要重写equals、hashCode

唯一性说明

下方有图示说明
1)首先比较每个对象的hash值。hash值如果不相等,对象一定不相等;如果相等,对象不一定相等。 但是在Object中:对象相等,hash值一定不相等。所以才有上文的but的描述
2)hash值不相等时,直接向集合中添加
3)hash值相等,判断equals
4)equals为ture,不向集合中添加
5)equals为false,向集合中添加

即,通过hashCode和equals保证数据唯一

public class demo_hashSet_唯一性 {

	public static void main(String[] args) {
		HashSet<Person> hs = new HashSet<Person>();
		hs.add(new Person("zs",18));
		hs.add(new Person("ls",17));
		hs.add(new Person("ww",58));
		hs.add(new Person("zs",18));
		hs.add(new Person("ls",17));
		hs.add(new Person("ww",58));
		hs.add(new Person("zs",18));
		hs.add(new Person("ls",17));
		hs.add(new Person("ww",58));
		for (Person person : hs) {
			System.out.println(person.toString());//自定义类,调用的toString()需要重写
		}
	}

}
class Person{
	private String name;
	private int age;
	
	//哈希值不相等,那么对象一定不相等;反之,不一定
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	……
	……

【图示1-1】
【图示1-2】

LinkedHashSet

①HashSet的子类,去重原理和HashSet一样。
②哈希存储。每个元素存储时,都记录了前后元素的地址。
可以根据存储元素的顺序,将元素取出
它的构造方法可以用于去重,并且不打乱顺序

public static void main(String[] args) {
		List<Integer> it = new ArrayList<Integer>();
		it.add(123);
		it.add(123);
		it.add(123);
		it.add(456);
		it.add(456);
		it.add(456);
		it.add(789);
		it.add(789);
		it.add(789);
		
		System.out.println(it);
		//使用LinkedHashSet子类的构造方法,来去重,并且不打乱顺序
		// ? extends E  ——》 it的泛型只能被包含于Integer
		LinkedHashSet<Integer> lhs = new LinkedHashSet<Integer>(it);
		System.out.println(lhs);
		
	}

Map

双列集合的顶层接口

对应关系

概述

单词
    Map:地图
双列集合
    每次操作时,都是针对一对数据进行操作,健key、值value
数据结构:描述的就是一个数据(key)到另一个数据(value)的映射关系
    key:有规则的,容易记忆的,简单的数据
    value:没有规则,不容易记忆,复杂的数据
对应关系
    1)逻辑关系——》y = x+1;
    2)穷举——》{1=2,2=3,3=4,4=5}
java中Map的对应关系
    就是使用穷举表示,key与value的对应关系
Map的特点
    1)key唯一,value不一定,但是最好唯一
    2)一个key只能对应一个value

常用方法

说明:K、V表示泛型;在创建时需要给Map规定key和value的类型
1)添加、修改:
  put(K key,V value),不存在相同的key,就添加;存在,就修改
2)删除、清空:
  remove(K key)

  clear()
3)获取:
  size(),获取键值对个数

  V get(K key),给定键,获取对应的值
4)判断:
  containsKey(Object obj),判断是否含有某个key
  containsValue(Object obj),判断是否含有某个value

		public class demo_Map_常用方法 {
		
			public static void main(String[] args) {
				Map<String, Integer> map = new HashMap<String, Integer>();
				map.put("abc", 123);
				map.put("abc", 456);
				System.out.println(map);//{abc=456}
				
				System.out.println(map.containsKey("abc"));//true
				System.out.println(map.containsValue(123));//false
				System.out.println(map.containsValue(456));//true
				
				map.put("def", 789);
				map.remove("def");
				System.out.println(map.get("def"));//null
				
				System.out.println(map.size());//1
			}
		}

【Map的遍历】

一、获取键

获取Map集合的所有键,放在一个Set集合中,遍历该Set集合,获取到每一个建,根据键来取值(先转单列集合,在获取值)

步骤:
1)获取所有的键:Set< K > KeySet()。返回Set集合中所有的键
2)遍历键(迭代器、增强for循环)
3)使用V get(K key)获取值

public class demo_Map_通过键遍历值 {

	public static void main(String[] args) {
		Map<String,Integer> map = new HashMap<String, Integer>();
		map.put("anc", 123);
		map.put("123", 123);
		map.put("jfj", 123);
		
		test_增强for循环(map);
		test_迭代器遍历(map);
	}

	private static void test_增强for循环(Map<String, Integer> map) {
		for (String key : map.keySet()) {
			System.out.println(key + "\t" + map.get(key));
		}
	}

	private static void test_迭代器遍历(Map<String, Integer> map) {
		//迭代器遍历
		Set<String> keys = map.keySet();
		
		Iterator<String> it = keys.iterator();
		while(it.hasNext()) {
			String key = it.next();
			int value = map.get(key);
			System.out.println(key + "\t" + value);
		}
	}

}

二、键值对对象

获取键值对对象(Entry)到Set集合中,在通过键值对获取键和值

Entry是Map的内部接口。常用方法getKey()、getValue()、setValue(V value)

步骤:
1)获取键值对对象,存放在Set集合中
    Set<Map.Entry<String, Integer>> entrySet()
2)遍历Set集合,获取每一个Entry对象
    迭代器、增强for循环
3)在根据Entry键值对获取相应的键和值
    getKey()、getValue()

public class demo_Map_通过键值对对象遍历 {

	public static void main(String[] args) {
		Map<String,Integer> map = new HashMap<String, Integer>();
		map.put("anc", 123);
		map.put("123", 123);
		map.put("jfj", 123);
		
		test_增强for循环(map);
		tets_迭代器遍历(map);
	}

	private static void test_增强for循环(Map<String, Integer> map) {
		//Entry是Map内部接口
		for (Map.Entry<String,Integer> entry : map.entrySet()) {
			System.out.println(entry.getKey() + "\t" + entry.getValue());
		}
	}

	private static void tets_迭代器遍历(Map<String, Integer> map) {
		//Entry是Map的内部接口,所以Set的泛型为Map.Entry,而键值对的泛型为<K key,V value>
		Set<Map.Entry<String, Integer>> entrys = map.entrySet();//得到键值对集合
		
		Iterator<Entry<String, Integer>> it = entrys.iterator();
		while(it.hasNext()) {
			Map.Entry<String, Integer> entry = it.next();//得到某个键值对
			String key = entry.getKey();//获取某个键值对的key
			Integer value = entry.getValue();//获取某个键值对的value
			System.out.println(key + "\t" + value);
		}
	}

}

Map实现类

HashMap
概述

Map的一个实现类

存储方式:
    哈希表存储,本质就是一个节点类型的数组

查询方式:
    根据键查找对应的值。根据键计算哈希值,通过哈希值找到节点

键的特点
    1)键值唯一,但是可以多次存储,相当于修改键对应的值
    2)通过equals()比较键值,自定义类注意重写hashcode、equals

HashMap与HashSet的关系
    1、不同
        1)HashMap双列集合,键唯一;HashSet单列集合,元素唯一
    2、关联
        1)保证唯一性的原理一样
        2)HashSet底层就是HashMap,只是把value的一列全用常量代替。相当于,HashSet存储元素,就是用HashMap存储键

LinkedHashMap

说明:
HashMapde子类,可以使用HashMap的方法,也是哈希存储

特点:
可预知的迭代顺序,即怎样的顺序存,怎样的顺序取
因为,每一个节点存取,下一个节点的逻辑地址

Collections

有关集合的工具类

前话

可变参数

参数可变,是指参数的个数可以改变。jdk1.5之后
类似方法重载,当不知道传入参数的个数时可以使用:类型 …变量名
【注意】
1)int …a,相当于int[] a。但是这样写,调用这个方法时,不用自个封装成数组之后,在调用该方法
2)可变参数,只能写在参数列表的最后。实际参数依次对应后,剩下的部分,分给可变参数

public class demo_可變參數 {

	public static void main(String[] args) {
		System.out.println(getSum());//0
		System.out.println(getSum(1,2));//3
		System.out.println(getSum(1,2,3));//6
		System.out.println(getSum(1,2,3,4));//10
	}
	public static int getSum(int ...a) {
		int sum = 0;
		for (int i = 0; i < a.length; i++) {
			sum += a[i];
		}
		return sum;
	}

}
【比较器】

自定义某个规则,用于比较两个数据的大小
所以比较器只是一个接口,需要自定义比较规则,不同的规则,对应不同的实现

接口:Comparator< T >
在比较器中,一般把小的放在o1,大的放在o2。如果想产生逆序的效果可以对换o1、o2

int compare(T o1,T o2)返回
o1 < o2负数
o1 = o20
o1 > o2正数
public class demo_比较器Comparator {

	public static void main(String[] args) {
		Person[] pers = {
				new Person("张三",17,175,120),
				new Person("李四",18,175,105),
				new Person("王老七",17,175,120),
				new Person("吉克隽逸",28,165,105),
				new Person("吉克",28,165,105),
				new Person("隽逸",28,166,105),
				new Person("吉逸",28,166,106),
		};
		
		for (Person person : pers) {
			System.out.println(person);
		}
		
		System.out.println("按照规则降序排序后为:");
		Arrays.sort(pers,new MyComparetor());
		for (Person person : pers) {
			System.out.println(person);
		}

	}

}


class MyComparetor implements Comparator<Person>{
			//年龄不一样,按照年龄降序排序
			//年龄一样时,按照名字长度降序排序
			//名字长度一样,按照身高降序排序
			//身高一样,按照体重降序排序
	@Override
	public int compare(Person per1,Person per2) {
		int age = per2.getAge() - per1.getAge();
		if(age != 0) {//说明age不相等
			return age;
		}else {
			int name = per2.getName().length() - per1.getName().length();
			if(name != 0) {//说明名字长度不相等
				return name;
			}
			else {
				int length = per2.getLength() - per1.getLength();
				if(length != 0) {//说明身高不相等
					return length;
				}else {
					int weet = per2.getWeet() - per1.getWeet();//weet——weight
					return weet;
				}
			}
		}
	}
}

class Person{
	private String name;
	private int age;
	private int length;
	private int weet;
	
	public Person() {
		super();
	}
	public Person(String name, int age, int length, int weet) {
		super();
		this.name = name;
		this.age = age;
		this.length = length;
		this.weet = weet;
	}
	//省略get、set方法
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", length=" + length + ", weet=" + weet + "]";
	}
}

【Collections常用方法】

【添加】

	collections(Collection c , 元素……)
	
	Collection<Integer> c = new ArrayList<Integer>();
	Collections.addAll(c, 1,2,3,4,5);
	System.out.println(c);

【升序】

	sort(List list)
 	根据List中的元素的原本比较方式,进行排序
	sort(List list, Comparator c)
 	根据比较器规定的规则,进行排序

【逆序】

	reverse(List list)
 	将list集合中的元素逆序
 	reverseOrder()
 	强行逆转要排序的集合中的元素的自然比较规则
 	reverseOrder(Comparator c)
 	强行逆转的是传入的比较器对象的比较规则

【统计】

	int frequency(Collection c, Object obj)
 	统计在c集合中,的obj的个数
 	
 	List<Integer> c1 = new ArrayList<Integer>();
	Collections.addAll(c1, 11, 88, 88, 22, 33, 22, 11);
	System.out.println(Collections.frequency(c1, 11));
	System.out.println(Collections.frequency(c1, 22));

【二分查找】

	int binarySearch(List<E> list,K key)
	binarySearch(List list, Comparator c, K key)
	在一个有升序排列的集合list中,通过二分查找键值为key的元素

【交换】

	swap(List<E> list,int a,int b)
	将指定列表的a索引和b索引对应的元素,进行交换

复制

	copy(List<? extends E> list1,List<? extends E> list2 )
	将元素列表,复制到另一个元素列表
	
	List<Integer> c1 = new ArrayList<Integer>();
	Collections.addAll(c1, 1,2,3,4,5,7);	
	List<Integer> c2 = new ArrayList<Integer>();
	Collections.addAll(c2, 1,2,3,4,6);
	//把c1的元素列表覆盖,覆盖不到的地方不管,但是去覆盖的列表长度不应该超过被覆盖的列表长度
	Collections.copy(c1, c2);
	System.out.println(c1);//1,2,3,4,6,7

打乱

	shuffle(List<E> list)
	将list列表中的元素,打乱

完全比较

	Boolean disjoint(Collection c1, Collection c2)
	比较两个集合中的元素,是否完全不同,只要有相同的元素,就返回false

一个集合中找另一个集合的索引

	int indexOfSubList(List source, List target)
 	在source集合中,查找target集合的索引
 	
 	List<Integer> c1 = new ArrayList<Integer>();
	Collections.addAll(c1, 11, 88, 88, 22, 33, 22, 11);
	List<Integer> subList = new ArrayList<Integer>();
	Collections.addAll(subList, 22, 33);
	System.out.println(Collections.indexOfSubList(c1, subList));

max、min

 	可以获取集合的最大值和最小值

替换

	replaceAll(List list, Object oldValue, Object newValue)
 	将list集合中的所有oldValue替换为newValue

后移

	roate(List list, int distant)
 	将集合进行轮换,让每个元素都向后移动distant个位置
 	前后为边界,就像学生换位置一样
 	
 	List<Integer> c1 = new ArrayList<Integer>();
	Collections.addAll(c1, 11, 66, 88, 22, 33, 55, 99);
	Collections.rotate(c1, -1);
	System.out.println(c1);

线程

	synchronizedXxx(Xxx xxx)
 	将线程不安全的集合转成线程安全的集合并返回

只读

	unmodifiableXxx(Xxx xxx)
 	将内容可以修改的集合,转换成只读的集合




练习



PS
1)【】、加粗表示重点;删除线表示已解决
2)学习记录实现,如有不妥还望指正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈年_H

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值