集合
集合本身是个对象(集合类的具体对象),作用是方便对多个对象进行操作
集合和数组的区别
只能存放对象 //不能是基本数据类型,但可以是包装类
存放的元素可以是多种类型 //默认是Object,如果放入泛型,只能放泛型指定的对象作为元素
长度是可变的 //可以增删,集合中元素被删除后, 后面的元素会向前进1
Collection
接口特点
元素是object类型(基本数据类型不能放入,需要改成包装类)
基本操作
add remove clear contains(比较的是equals) size isEmpty
两个集合间的基本操作
addAll removeAll containsALL retainAll 取交集
遍历
toArray方法(集合转数组) iterator方法(迭代器) foreach方法
由于collection是单列集合的根接口,其子类都可以这样进行遍历
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
//collection的三种遍历
public class Jih {
public static void main(String[] args) {
Collection c= new ArrayList();
c.add(123);//此时放入的是Integer类型,而不是int,只能存放对象
c.add("china");//可以存放多种数据类型,且长度可变
c.add(new Person("张三",18));
//toarray 集合转数组
Object[] array = c.toArray(); //toarray方法返回的是Object类型,无法调用本身的方法
for(Object ob:array){
System.out.println(ob);
}
System.out.println("-------------");
//iterator
Iterator it = c.iterator(); //如果有泛型 需要加上<>,如果不加 返回的数Object类型,无法调用自身方法
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("-------------");
//foreach //增强for循环可以直接对集合进行遍历,十分方便;但元素所在类必须实现iterable接口
for(Object ob:c){ //如果没有泛型,返回的是Object,有泛型返回具体类型
System.out.println(ob);
}
}
}
class Person{
String name;
int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
List
接口特点
可重复,有序
//可以使用索引查询元素 可以用于遍历 list.get(index) list.set(index,object)
基本操作
add(index,object) //挤进去 同时也有add(object)
remove (index) //同时也有remove(object),删除元素后,后面元素向前进1
get(index) //用于遍历集合 set(index,object) //修改元素
ListIterator 迭代器
遍历、去重、排序
list.get(index) ListIterator + collection的三种
去重使用set集合,依据hashcode和equals
排序使用集合工具类的sort方法
实现类
Arrayslist 底层是数组 增删慢,查找快
LinkedList 底层是链表 增删块,查询慢
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
//list遍历的五种方法
public class Jih {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();//加上泛型,此时list只能存放Person类的对象
list.add(new Person("张三", 18));
list.add(new Person("李四", 18));
list.add(new Person("王五", 18));
list.add(new Person("赵六", 18));
//list独有的方法 list.get(index)
for(int i = 0;i < list.size();i++){ //可以获得索引及其对应的值
System.out.println(list.get(i));
}
System.out.println("-------------");
//listIterator迭代器
ListIterator<Person> listIterator = list.listIterator(); //迭代器中也要加上泛型
while(listIterator.hasNext()){
System.out.println(listIterator.next());
}
System.out.println("-------------");
//iterator
Iterator<Person> iterator = list.iterator();//迭代器中也要加上泛型
while (iterator.hasNext()) {
System.out.println(iterator.next().name);
}
System.out.println("-------------");
//其他两种不做演示
}
}
class Person{
String name;
int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
list遍历和去重的例题
1.获取Person集合中年龄大于20的对象的集合;
import java.util.ArrayList;
import java.util.List;
public class Jih {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("张三",12));
list.add(new Person("张si",28));
list.add(new Person("张wi",12));
list.add(new Person("张liu",27));
list.add(new Person("张三",29));
list.add(null); //元素可以是null,但在后面调用.age时会报空指针异常,下面需要判断是否为null
List<Person> ps = new ArrayList<>();
for (Person person : list) { //遍历
if(person!=null && person.age>20){ //必须要判断person不为null,否则会空指针异常;&&不能换成单&,前后有推导关系
ps.add(person);
}
}
System.out.println(list);
list.clear(); //清空list集合
list.addAll(ps); //将ps集合添加到list集合,实现list集合中去除年龄小于20的元素
System.out.println(list);
}
}
class Person {
String name ;
int age;
public Person(String name, int age) { //有参构造
super();
this.name = name;
this.age = age;
}
@Override
public String toString() { //tostring
return "Person [name=" + name + ", age=" + age + "]";
}
}
- 对list中的元素去重;两种方法,后面还有用set去重的方法,是最简单的,这两种只做了解
import java.util.ArrayList;
import java.util.List;
public class Jih {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("张三", 12));
list.add(new Person("张三", 29));
list.add(new Person("李四", 12));
list.add(new Person("李四", 12));
list.add(new Person("张三", 29));
// 方法1
// 创建list2,判断list中的元素是否在list2中(list2.contains(list1.get(index)),不在就add添加
List<Person> ps = new ArrayList<>();
for (Person person : list) { // 增强for循环只能得到对象,不能得到list的索引值
if (!ps.contains(person)) { // 这里是person是对象
ps.add(person);
}
}
System.out.println(ps);
System.out.println(ps.size());
//方法二:想到了数组的去重,用第i个元素和后面元素做比较(equals),如果相同就把后面的去掉(remove),
//但与数组的区别是,数组取出后,那个位置还存在,集合会自动向前缩进
for (int i = 0; i < list.size() - 1; i++) {
for (int j = i + 1; j < list.size(); j++) {
if (list.get(i).equals(list.get(j))) { // equals默认比较地址值,需要重写,比较属性值
list.remove(j);
j--; //因为list中元素删除后,后面的元素会自动向前缩进一个
}
}
}
System.out.println(list);
System.out.println(list.size());
}
}
class Person {
String name;
int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + 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;
}
}
set
接口特点
无序,不可重复 // 必须提前重写hashcode和equals
遍历、去重、排序
collection的三种
自带去重,必须提前重写hashcode和equals
排序先转为list,使用集合工具类的sort方法
实现类
HashSet 底层是哈希,不能保证存入和取出的顺序
linkedHashset 底层是哈希+链表 可以保证存入和取出的顺序
Set去重的例题
-
定义10个1-20之间的随机数:使用linkedhashset编写一个程序,获取10个1-20之间的随机数,要求随机数不能重复;
//当时用数组做是多么的麻烦(双色球那道题),去重 选用set就很简单,然后再转回数组
import java.util.LinkedHashSet;
import java.util.Random;
import java.util.Set;
public class Hjas {
public static void main(String[] args) {
Set<Integer> set = new LinkedHashSet<>();
while(set.size()<10){
set.add(new Random().nextInt(20)+1);
}
System.out.println(set);
}
}
-
利用set对list进行去重:给定一个Person的list集合,添加几个元素,对其去重
//相比于上面提到的方法,这个方法不需要进行循环
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Hjas {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("张三",12));
list.add(new Person("张三",29));
list.add(new Person("李四",12));
list.add(new Person("李四",12));
list.add(new Person("张三",29));
Set<Person> set= new HashSet<>(list);//提前重写Person类的hashcode和equals方法
list.clear();
list.addAll(set);
System.out.println(list);
System.out.println(list.size());
}
}
class Person {
String name ;
int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + 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;
}
}
Map
接口特点
key和value作为一个entry成对存在;
key不能重复(必须提前重写hashcode和equals) ,可以为null
key一般较简单为了查value
基本操作
put(k,v) remove(k) clear() containskey(k) containsvalue(v) size()
map.get(key) 得到values map.values() 返回value的集合
遍历、去重
keyset entryset values
自带去重,只对key去重,必须提前修改key的hashcode和equals
排序 如何对values进行排序呢 entry成set,用sort排序
实现类
HashMap 本质是数组 其元素为链表 不能保证存入和取出的顺序
LinkedHashMap 可以保证存入和取出的顺序 ???
import java.security.KeyStore.Entry;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Jih {
public static void main(String[] args) {
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 1);
map.put(2, 2);
map.put(3, 3);
map.put(4, 4);
//keyset
Set<Integer> keyset =map.keySet();
for(Integer key : keyset){
System.out.println("key:" + key+ " value: "+map.get(key));
}
System.out.println("-----------");
//entryset
Set<java.util.Map.Entry<Integer,Integer>> entryset = map.entrySet();
for(java.util.Map.Entry<Integer,Integer> entry: entryset){
System.out.println("key:" + entry.getKey() + "values:" + entry.getValue());
}
System.out.println("-----------");
//map.values
Collection<Integer> values = map.values();
for(Integer v:values){
System.out.println(v);
}
}
}
import java.util.HashMap;
import java.util.Map;
//統計每個明星捐款次數和總金額
public class Hasxaet {
public static void main(String[] args) {
String s = "范冰冰,10000;成龙,20000;范冰冰,10000;成龙,2334;李连杰,2999";
Map<String, Mon> mp = new HashMap<>();
String[] sp = s.split(";"); //将字符串进行分割,得到元素为字符串的数组 split
for (String ss : sp) { //遍历sp数组,将字符串进行分割,得到元素为字符串的数组 split
String name = ss.split(",")[0];
int money = Integer.valueOf(ss.split(",")[1]);
if (!mp.containsKey(name)) {
mp.put(name, new Mon(1, money));
} else {
mp.put(name,
new Mon(mp.get(name).count + 1, mp.get(name).money + money));
}
}
System.out.println(mp);
}
}
class Mon {
int count;
int money;
public Mon(int count, int money) {
super();
this.count = count;
this.money = money;
}
@Override
public String toString() {
return "Mon [count=" + count + ", money=" + money + "]";
}
}
集合和数组的相互转化
集合转数组
Object[] ob = list.toArray(); //返回object类型的数组,需要向下转型
数组转集合
list<> list= new Arraylist<>(Arrays.aslist()); //不能增加元素
list和set相互转化
对list去重,
对set使用集合工具类进行操作;
如果相对list进行去重排序,可以转为treeset
Set<Object> set = new HashSet<>(); //创建set
List<Object> list = new ArrayList<>(set); //将其转为list
List<Object> list2 = new ArrayList<>(); // 创建list2
Set<Object> set2 = new HashSet<>(list2);//将其转为set2
数组工具类Arrays
Arrays.toString Arrays.sort 升序 Arrays.aslist() 创建数组
Arrays.binarysearch(arr,value) 必须先排序为升序,查找value对应的index,
集合工具类Collections
只对list进行操作
sort(list) max(list/set) reverse(list) shuffle(list) 乱序
binarysearch(list,value) //必须先排序为升序,查找value对应的index
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
/*
* 模拟斗地主的发牌,54张牌先洗牌(shuffl),然后分给三个人,留三张牌作地主牌,最后到手的牌需要排序
*/
public class Tssss {
public static void main(String[] args) {
String[] color = new String[] { "♥", "♦", "♠", "♣" };
String[] num = new String[] { "2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3" };
HashMap<Integer, String> pai = new HashMap<>();
int x = 1;
pai.put(x++,"小王");
pai.put(x++,"大王");
for (int j = 0; j < num.length; j++) {
for (int i = 0; i < color.length; i++) {// 先循环num在循环花色,让四种花色的同样大小的牌编号离得近一点
pai.put(x, color[i] + num[j]);// 存放牌号(1-54) 和 对应的牌 花色+大小
x++;
}
}
ArrayList<Integer> pai2 = new ArrayList<>(pai.keySet());
Collections.shuffle(pai2);
List<Integer> A = new ArrayList<>(); // 存放A对应的手里的牌号
List<String> AA = new ArrayList<>(); // 存放A手里的牌
List<Integer> B = new ArrayList<>();
List<String> BB = new ArrayList<>();
List<Integer> C = new ArrayList<>();
List<String> CC = new ArrayList<>();
List<Integer> D = new ArrayList<>(); // 底牌对应的牌号
List<String> DD = new ArrayList<>(); // 底牌
for (int i = 0; i < pai2.size(); i++) {
if (i >= 51) {
D.add(pai2.get(i));
} else if (i % 3 == 0) {
A.add(pai2.get(i));
} else if (i % 3 == 1) {
B.add(pai2.get(i));
} else if (i % 3 == 2) {
C.add(pai2.get(i));
}
}
getPai(A, AA, pai);
getPai(B, BB, pai);
getPai(C, CC, pai);
getPai(D, DD, pai);
System.out.println("A手里的牌为:" + AA);
System.out.println("B手里的牌为:" + BB);
System.out.println("C手里的牌为:" + CC);
System.out.println("底牌为:" + DD);
}
public static void getPai(List<Integer> A, List<String> AA, HashMap<Integer, String> pai) {
Collections.sort(A); // 牌号进行排序
for (Integer integer : A) {
AA.add(pai.get(integer)); // 根据牌号取出对应的牌
}
}
}
比较器
comparable
内部比较器,使用Collections.sort(list)排序 ,元素所在类实现此接口并重写compareTo方法
comparator
外部比较器,重写compare方法
TreeSet/TreeMap
必须传入比较器,key不能为null
自带去重和排序且均按照比较器规则进行(不是equals),最好设置多个条件
集合排序例题
- 建立Person的list集合,先按照年龄升序;再按照name降序 (implements Comparable)
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Hjas {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("张三", 14));
list.add(new Person("李四", 17));
list.add(new Person("王五", 23));
list.add(new Person("赵六", 14));
list.add(new Person("钱七", 14));
list.add(new Person("王八", 24));
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}
}
class Person implements Comparable<Person> { //实现内部比较器
String name ;
int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
@Override
public int compareTo(Person o) {
if(this.age == o.age){
return o.name.compareTo(this.name) ;
}
return this.age>o.age?1:-1; //避免小数
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Hjas {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person("张三", 14));
list.add(new Person("李四", 17));
list.add(new Person("王五", 23));
list.add(new Person("赵六", 14));
list.add(new Person("钱七", 14));
list.add(new Person("王八", 24));
System.out.println(list);
//方法1
/*Collections.sort(list,new Comparator<Person>() { //外部比较器
@Override
public int compare(Person o1, Person o2) {
if(o1.age==o2.age){ //先按照年龄升序;再按照name降序
return o2.name.compareTo(o1.name);
}
return o1.age-o2.age;
}
});
System.out.println(list);
System.out.println("---------------------------------");*/
//方法2
list.sort(new Comparator<Person>() { //外部比较器
@Override
public int compare(Person o1, Person o2) {
if(o1.age==o2.age){ //先按照年龄升序;再按照name降序
return o2.name.compareTo(o1.name);
}
return o1.age-o2.age;
}
});
System.out.println(list);
System.out.println("---------------------------------");
//方法3 lanbda表达式 后面有一章重点讲
Collections.sort(list,(a,b)->(a.age-b.age)); //这种的如果比较两种条件就比较麻烦,如果比较条件就一个,使用lambda简单
System.out.println(list);
System.out.println("---------------------------------");
Collections.sort(list,(a,b)->(a.name.compareTo(b.name)));//单独以name为条件
System.out.println(list);
}
}
class Person{
String name ;
int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
- 创建一个学生类,包含姓名 语文成绩 数学成绩 英语成绩 键盘录入三个学生对象,按照总分降序排序,总分相同 按照语文成绩降序排序,语文相同按照数学成绩降序排序,数学相同按照姓名升序排序
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;
public class Test{
public static void main(String[] args) {
ArrayList<student> list = new ArrayList<>();
Scanner sc = new Scanner(System.in);
for (int i = 0; i < 3; i++) {
System.out.println("名字");
String name = sc.next();
System.out.println("yw");
double yw = sc.nextDouble();
System.out.println("sx");
double sx = sc.nextDouble();
System.out.println("yy");
double yy = sc.nextDouble();
list.add(new student(name, yw, sx, yy));
}
list.sort(new Comparator<student>() {
@Override
public int compare(student o1, student o2) {
return o2.yw + o2.sx + o2.yy > o1.yw + o1.sx + o1.yy ? 1
: o2.yw + o2.sx + o2.yy < o1.yw + o1.sx + o1.yy ? -1
: o2.yw > o1.yw ? 1
: o2.yw < o1.yw ? -1
: o2.sx > o1.sx ? 1 : o2.sx < o2.sx ? 1 : o1.name.compareTo(o2.name);
}
});
System.out.println(list);
}
}
class student {
String name;
double yw;
double sx;
double yy;
public student(String name, double yw, double sx, double yy) {
super();
this.name = name;
this.yw = yw;
this.sx = sx;
this.yy = yy;
}
@Override
public String toString() {
return "student [name=" + name + ", yw=" + yw + ", sx=" + sx + ", yy=" + yy + "]";
}
}
- 对TreeMap和TreeSet进行去重排序(TreeSet其实和TreeMap差不多)
import java.util.Comparator;
import java.util.TreeMap;
public class MapDemo {
public static void main(String[] args) {
//只定义age,则去重和比较都是按照age进行 2个元素 保留先放进去的元素
/*Map map = new TreeMap<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.age-o2.age;
}
});*/
//只定义name,则去重和比较都是按照name进行 4个元素 保留先放的
/*Map map = new TreeMap<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o1.name.compareTo(o2.name);
}
});*/
//先按照age升序,再按照name降序 5个元素 重复的话保留后放入的,等同于对元素进行修改
Map map = new TreeMap<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
if(o1.age == o2.age){
return o2.name.compareTo(o1.name);
}
return o1.age - o2.age ;
}
});
map.put(new Person("zhangsan", 12),1);
map.put(new Person("zhangsan", 12),2);
map.put(new Person("zhang", 12),1);
map.put(new Person("zhang", 13),1);
map.put(new Person("san", 12),1);
//map.put(null, 12); treeMap和TreeSet中的key不能为null,排序和去重都是依据的key
map.put(new Person("si", 12),1);
System.out.println(map); //如果不构建比较器,直接打印会报错
System.out.println(map.size());
}
}
class Person{
String name;
int age;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
泛型
如果不加泛型,集合可以装Object(任何对象),混装;在遍历集合时,取出的都是object类型,无法直接调用对象的方法,需要向下转型;
主要用于限制集合中的元素类型,使集合中元素类型一致;
foreach
方便对集合或数组进行遍历; 其底层还是迭代器,只要实现了iterable接口就可以使用foreach
for(数据类型 变量i: 集合/数组)
需要注意,此时 变量i 就是集合或数组中的一个元素(对象),无法得到索引值;
可变参数
在参数列表上 (参数类型**…** a) 只能存在1个 放在最后 其本质是数组
集合的重点总结
1. 根据集合的特点,选取特定的集合进行分析
list 有序可重复 可用set去重 可以用集合工具类操作(排序,查找,反转 最值)
set 无序不可重复 常用于去重 可转为list使用集合工具类
map 储存键值对 key不能重复
Treemap 去重自动排序 根据比较器进行去重和排序(最好设置多个条件) key不能为null
2. 集合的遍历 去重 排序
遍历: 集合无法像数组那样用索引取值(list除外),因此如何遍历很重要
collection 3种 list 5种 set 3种 map 3种(可扩展)
去重: hashcode&equals (contains 方法 本质也是调用equals)
排序: list和set均可以用集合工具类sort进行排序;
TreeSet和TreeMap依据比较器进行去重和排序
3. 集合的快速遍历
lambda表达式
list.foreach(s->system.out.println(s))
map.foreach((a,b)->sysotem.out.println(a+":"+b))