目录
集合
集合是java中提供的一种容器,可以用来存储多个数据。
集合和数组的区别:
- 数组的长度是固定的。集合的长度是可变的。
- 数组存储的是同一类型的数据(基本数据类型、引用数据类型),集合存储的都是对象(对象的类型可以不一致)
集合框架
List接口的特点:元素有序、元素可重复、有索引
Set接口的特点:元素无序、元素不可重复、无索引(没有索引,不能使用普通for循环遍历)
Collection类
Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法。
- public boolean add(E e):把给定的对象添加到当前集合中
- public void clear():清空集合中所有的元素
- public boolean remove(E e):把给定的对象在当前集合中删除
- public boolean contains(E e):判断当前集合中是否包含给定的对象
- public boolean isEmpty():判断当前集合是否为空
- public int size():返回集合中元素的个数
- public Object[] toArray():把集合中的元素,存储到数组中
示例代码:
public static void main(String[] args) {
Collection<String> collection=new ArrayList<>();
//添加元素
collection.add("A"); collection.add("B");collection.add("C");collection.add("D");
System.out.println(collection);//[A, B, C, D]
collection.remove("A");//删除"A"这个对象
System.out.println(collection);//[B, C, D]
System.out.println(collection.isEmpty());//集合不为空 返回false
System.out.println(collection.contains("B"));//集合包含"B"对象,返回true
System.out.println(collection.size());//集合的长度为3
Object[] objects = collection.toArray();//将集合转换成对象数组
for (Object object : objects) {
System.out.print(object+"\t");//B C D
}
System.out.println();
collection.clear();//清空集合
System.out.println(collection);//[]
}
Iterator迭代器
迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
获取迭代器的方法:public Iterator iterator() 获取集合对应的迭代器
Iterator接口的常用方法:
- public E next() :返回迭代的下一个元素(两个动作:先返回下一个元素,再向后移动指针)
- public boolean hasNext():如果仍有元素可以迭代,则返回 true
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素
增强for(for each)
专门用来遍历数组、集合,内部原理其实是一个Iterator迭代器。在遍历过程中,不能对元素进行增删操作
示例代码:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三");list.add("李四");list.add("王五");
//迭代器方法实现遍历
//while形式
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
System.out.print(iterator.next()+'\t');//张三 李四 王五
}
System.out.println();
//for形式
for(Iterator<String> iterator1=list.iterator();iterator1.hasNext();){
System.out.print(iterator1.next()+'\t');张三 李四 王五
}
System.out.println();
//for each遍历集合
for (String s : list) {
System.out.print(s+'\t');张三 李四 王五
}
}
泛型
可以在类或方法中预支地使用未知的类型,当没有指定泛型时,默认类型为Object类型。
泛型的好处:
- 避免了类型转换
- 把运行期异常提升到了编译期
含有泛型的类
public class test1 <E>{
private E mvp;
public E getMvp() {
return mvp;
}
public void setMvp(E mvp) {
this.mvp = mvp;
}
}
在创建对象的时候确定泛型
含有泛型的方法
public <E> void show(E e){
System.out.println(e);
}
调用方法时确定泛型
含有泛型的接口
public interface test3 <E>{
E getArray(E e);
}
- 在实现类中确定泛型
public class impl2 implements test3<String>{
@Override
public String getArray(String s) {
return s;
}
}
- 在创建对象时确定泛型
public class test3impl1<E> implements test3 <E>{
@Override
public E getArray(E e) {
return e;
}
}
泛型通配符(修饰在在方法的形参上)
不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符。
public static void test(ArrayList<?>list){
Iterator<?> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
方法功能:可以遍历各种类型的ArrayList
高级使用:
// 泛型的上限:此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(Collection<? extends Number> coll){}
// 泛型的下限:此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(Collection<? super Number> coll){}
Collections类:集合工具类
- Collections.sort(list) :将集合升序
- Collections.reverse(list):将集合反转
- Collections.shuffle(list):将集合乱序
综合案例:斗地主
public static void main(String[] args) {
ArrayList<String> list_1 = new ArrayList<>();//存储花色
ArrayList<String> list_2 = new ArrayList<>();//存储数字
ArrayList<String> list_3 = new ArrayList<>();//存储牌面
ArrayList<String> player1 = new ArrayList<>();//玩家一
ArrayList<String> player2 = new ArrayList<>();//玩家二
ArrayList<String> player3 = new ArrayList<>();//玩家三
ArrayList<String> dipai = new ArrayList<>();//底牌
list_1.add("♠");list_1.add("♥");list_1.add("♣");list_1.add("♦");
for (int i = 2; i <11 ; i++) {
list_2.add(i+"");
}
list_2.add("J"); list_2.add("Q"); list_2.add("K"); list_2.add("A");
for(String a:list_1){
for(String b:list_2){
list_3.add(a+b);
}
}
list_3.add("大王");list_3.add("小王");
Collections.shuffle(list_3);
for(int i=0;i<list_3.size();i++){
if(i>=50){
dipai.add(list_3.get(i));
}else {
if(i%3==0){
player1.add(list_3.get(i));
}else if(i%3==1){
player2.add(list_3.get(i));
}else {
player3.add(list_3.get(i));
}
}
}
System.out.println("斗地主游戏");
System.out.println("玩家一:"+player1);
System.out.println("玩家二:"+player2);
System.out.println("玩家三:"+player3);
System.out.println("底牌:"+dipai);
}
List集合
特点:
- 它是一个元素存取有序的集合
- 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素
- 集合中可以有重复的元素
List接口的常用方法(根据索引来操作集合)
- public void add(int index, E element):将指定的元素,添加到该集合中的指定位置上
- public E get(int index):返回集合中指定位置的元素
- public E remove(int index):移除列表中指定位置的元素, 返回的是被移除的元素
- public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("张三");list.add("李四");list.add("王五");
list.add(1,"钱二");//将元素添加到第二个位置上
System.out.println(list);//[张三, 钱二, 李四, 王五]
list.set(1,"赵六");//修改元素
System.out.println(list);//[张三, 赵六, 李四, 王五]
list.remove(0);//删除元素
System.out.println(list);//[赵六, 李四, 王五]
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i)+"\t");//赵六 李四 王五
}
}
ArrayList集合
集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。
LinkedList集合
集合数据存储的结构是链表结构。方便元素添加、删除的集合
- public void addFirst(E e):将指定元素插入此列表的开头。
- public void addLast(E e):将指定元素添加到此列表的结尾(和add()功能相同)
- public E getFirst():返回此列表的第一个元素。
- public E getLast():返回此列表的最后一个元素
- public E removeFirst():移除并返回此列表的第一个元素
- public E removeLast():移除并返回此列表的最后一个元素
- public E pop():从此列表所表示的堆栈处弹出一个元素(和removeFirst()功能相同)
- public void push(E e):将元素推入此列表所表示的堆栈(和addFirst(E e)功能相同)
public static void main(String[] args) {
LinkedList<String> list1 = new LinkedList<>();
list1.add("a");
list1.addFirst("b");
list1.push("c");
list1.addLast("d");
System.out.println(list1);//[c, b, a, d]
list1.removeFirst();
list1.removeLast();
list1.pop();
System.out.println(list1);//[a]
}
Set集合
Set集合的特点:无序、不能重复、没有索引
HashSet集合(不能保证 存入、取出的顺序相同)
是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。保证元素唯一性的方式依赖于:hashCode与equals方法。
保证HashSet集合的唯一性:
- 通过hashCode方法,获取哈希值
- 根据哈希值计算存储位置,哈希值%表长(默认值16)
- 该位置有无元素存在,如果没有元素,就将元素存储在该位置
- 如果位置上有元素,遍历该位置的所有元素,比较哈希值是否相同,如果不同则将元素存储在该位置
- 如果哈希值相同,调用equals方法比较对象内容是否相等,如果不相等则将元素存储在该位置
- 如果相等,元素重复,不存储
给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一
定义Student类 成员属性name、age,重写hashCode和equals
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
在main进行测试:
public static void main(String[] args) {
HashSet<Student> hashSet = new HashSet<>();
hashSet.add(new Student("张三",23));
hashSet.add(new Student("李四",12));
hashSet.add(new Student("王五",23));
hashSet.add(new Student("王五",23));//添加重复元素
for (Student student : hashSet) {
System.out.print(student);//Student{name='张三', age=23}Student{name='王五', age=23}Student{name='李四', age=12}
}
}
LinkedHashSet集合
它是链表和哈希表组合的一个数据存储结构。链表保证元素有序,哈希表保证元素唯一
-
public static void main(String[] args) { LinkedHashSet<Student> hashSet = new LinkedHashSet<>(); hashSet.add(new Student("张三",23)); hashSet.add(new Student("李四",12)); hashSet.add(new Student("王五",23)); hashSet.add(new Student("王五",23));//添加重复元素 for (Student student : hashSet) { System.out.print(student);//Student{name='张三', age=23}Student{name='李四', age=12}Student{name='王五', age=23} } }
可变参数(已知参数类型,不确定参数个数时可以使用)
同样是代表数组,但是在调用这个带有可变参数的方法时,不用创建数组
如果在方法书写时,这个方法拥有多参数,参数中包含可变参数,可变参数一定要写在参数列表的末尾位置。
public static void main(String[] args) {
System.out.println(sum(1,2,3));//6
System.out.println(sum(2,3,4,5));//14
}
public static int sum(int...a){
int sum=0;
for (int i : a) {
sum+=i;
}
return sum;
}
设置比较规则
自然排序:实现Comparable接口
- 自定义类实现Comparable接口
- 重写compareTo()
为Student重写compareTo()方法
@Override
public int compareTo(Student student) {
int num = this.age - student.getAge();//主条件相同时,需要设置次条件
return num==0?this.name.compareTo(student.getName()):num;
}
定义比较器(通常使用匿名内部类来实现)
- 自定义类实现Comparator接口
- 重写Compare方法
Collections.sort(students, new Comparator<Student>() {
@Override
public int compare(Student student, Student t1) {
int num=student.getAge()-t1.getAge();
return num==0?student.getName().compareTo(t1.getName()):num;
}
});
补充:Collections.sort方法需要借助比较规则来完成
自然排序与比较器的区别:
- 比较器是一个独立的比较规则(类似于一个第三方的工具)
- 如果自然排序和比较器都存在,以比较器为主
Map集合(双列集合)
存储方式为键值对
特点:键不能重复,值可以重复。每一个键只能对应一个值
Map接口的常用方法
- public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中
- public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
- public V get(Object key) 根据指定的键,在Map集合中获取对应的值
- public Set<K> keySet() : 获取Map集合中所有的键,存储到Set集合中
- public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)
示例代码:
public static void main(String[] args) {
Map<String, String> map = new HashMap<>();
//添加元素
map.put("001","张三");map.put("002","李四"); map.put("003","王五");
map.put("004","赵六");map.put("004","钱二");//添加元素时,key值相同时,value会被替代
System.out.println(map);//{001=张三, 002=李四, 003=王五, 004=钱二}
map.remove("003");//删除元素
System.out.println(map);//{001=张三, 002=李四, 004=钱二}
System.out.println(map.get("001"));//根据键获得指定元素
}
Map集合的遍历方法:
1、键找值的方式
Set<String> keySet = map.keySet();
for (String key : keySet) {
String value = map.get(key);
System.out.println(key+"======"+value);
}
2、遍历键值对的方式
Set<Map.Entry<String, String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey()+"====="+entry.getValue());
}
Entry是键值对对象
HashMap集合
特点:无序,存入和取出的顺序可能不一样
存储自定义类型键值:当给HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须复写对象的hashCode和equals方法
LinkedHashMap集合
它是链表和哈希表组合的一个数据存储结构
特点:存入和取出的顺序一样
JDK9对集合添加的优化
of()方法只是Map,List,Set这三个接口的静态方法,其父类接口和子类实现并没有这类方法,比如
HashSet,ArrayList等待;返回的集合是不可变的;
List<Integer> list = List.of(1, 2, 3, 4, 5, 6, 2);//[1, 2, 3, 4, 5, 6, 2]
Set<Integer> integers = Set.of(1, 2, 3, 4, 5, 6);//[2, 1, 6, 5, 4, 3]
Map<Integer, String> map1 = Map.of(1, "a", 2, "b");//{2=b, 1=a}
综合案例:斗地主
案例分析:花色、数字存放在list中,map存放编号和牌面(花色+数字),获取map的编号集合,将其打乱,分发给4个集合;通过分发的编号 获得相应的牌面
public static void main(String[] args) {
ArrayList<String> list_1 = new ArrayList<>();//花色
ArrayList<String> list_2 = new ArrayList<>();//数字
HashMap<Integer, String> hashMap = new HashMap<>();//编号:牌面
ArrayList<Integer> list = new ArrayList<>();//编号打乱
ArrayList<Integer> nlist_1 = new ArrayList<>();//分发编号
ArrayList<Integer> nlist_2 = new ArrayList<>();
ArrayList<Integer> nlist_3 = new ArrayList<>();
ArrayList<Integer> nlist_4 = new ArrayList<>();
ArrayList<String> player1 = new ArrayList<>();//牌面
ArrayList<String> player2 = new ArrayList<>();
ArrayList<String> player3 = new ArrayList<>();
ArrayList<String> dipai = new ArrayList<>();
Collections.addAll(list_1,"♠","♥","♦","♣");
Collections.addAll(list_2,"A","2","3","4","5","6","7","8","9","10","J","Q","K");
int count=1;
hashMap.put(count++,"大王");
hashMap.put(count++,"小王");
for (String s : list_1) {
for (String s1 : list_2) {
hashMap.put(count++,s+s1);
}
}
Set<Integer> keySet = hashMap.keySet();
list.addAll(keySet);
Collections.shuffle(list);
for (int i = 0; i < list.size(); i++) {
if (i>50){
nlist_4.add(list.get(i));
}else if(i%3==0){
nlist_1.add(list.get(i));
}else if(i%3==1){
nlist_2.add(list.get(i));
}else{
nlist_3.add(list.get(i));
}
}
for (Integer integer : nlist_1) {
player1.add(hashMap.get(integer));
}
for (Integer integer : nlist_2) {
player2.add(hashMap.get(integer));
}
for (Integer integer : nlist_3) {
player3.add(hashMap.get(integer));
}
for (Integer integer : nlist_4) {
dipai.add(hashMap.get(integer));
}
System.out.println("斗地主游戏");
System.out.println("玩家一:"+player1);
System.out.println("玩家二:"+player2);
System.out.println("玩家三:"+player3);
System.out.println("底牌:"+dipai);
}