Java 集合
目录
Java 集合1. Collection集合(单列集合)集合概述
集合的架构Collection常用的方法Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(list和set)通用的一些方法,这些方法可用于操作所有的单列集合,共性方法如下:
import java.util.ArrayList; import java.util.Collection; /* public boolean add(E e); public void clear(); public boolean remove(E e); public int size(); public boolean isEmpty(); public Object[] toArray(); public boolean contains(E e); */ public class DemoCollection { public static void main(String[] args) { Collection<String> coll = new ArrayList<>(); System.out.println(coll); // add 添加元素 coll.add("迪丽热巴"); coll.add("古力娜扎"); coll.add("马尔扎哈"); coll.add("鹿晗"); coll.add("赵丽颖"); System.out.println(coll); // isEmpty 判断是否为空 System.out.println(coll.isEmpty()); // size 当前集合的大小 System.out.println(coll.size()); // remove 清除一个元素 coll.remove("马尔扎哈"); // Object[] toArray Object[] objects = coll.toArray(); for (int i = 0; i < objects.length; i++) { System.out.println(objects[i]); } // contains 判断当前集合是否包含给定的对象 boolean b1 = coll.contains("赵丽颖"); System.out.println(b1); // clear 清空集合中的元素,但集合仍然存在,只不过为空 coll.clear(); System.out.println(coll.isEmpty()); } } Iterator
有两个常用的方法
Iterator迭代器,是一个接口,我们无法直接使用,需要使用Iterator接口的实现类对象,获得实现类的方式比较特殊,Collection接口中有一个方法,叫iterator(),这个方法返回的就是迭代器的实现对象。
Iterator迭代器的使用步骤:
迭代器的实现原理 public class DemoCollection { public static void main(String[] args) { Collection<String> coll = new ArrayList<>(); coll.add("迪丽热巴"); coll.add("马儿扎哈"); coll.add("赵丽颖"); coll.add("鹿晗"); Iterator<String> it = coll.iterator(); while (it.hasNext()){ String str = it.next(); System.out.println(str); } } }
2. 增强for(for each)
for (元素的数据类型 变量名称 : Collection集合 or 数组){ // 写操作代码 }
3. 泛型(Generic)泛型概念泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,就可以使用泛型。 E e:Element 元素 创建集合对象的时候,就会确定泛型的数据类型。 使用泛型的好处创建集合对象,不使用泛型
创建集合,使用泛型
定义含有泛型的类
修饰符 class 类名<泛型>{ // ... }
public class GenericClass <E> { private E name; public void setName(E name){ this.name = name; } public E getName(){ return this.name; } } 定义含有泛型的方法泛型定义在方法的修饰符和返回值类型之间
修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){ // ... }
public class GenericMethod { // 定义泛型普通方法 public <E> void methodNormal(E e){ System.out.println(e); } // 定义泛型静态方法 public static <E> void methodStatic(E e){ System.out.println(e); } } 定义含有泛型的接口
修饰符 interface 接口名称<泛型>{ // ... }
public interface Iterator`<E>`{ E next(); } Scanner类实现了Iterator接口,并指定接口的泛型为String,所以重写的next方法泛型默认就是String。 public final class Scanner implements Iterator<String>{ public String next(); }
public class ArrayList<E>implements List<E>{ public boolean add(E e); public E get(int index); } public interface List<E> extends Collection<E> { boolean add(E e); E get(int index); } 泛型的通配符
/* 题目要求: 定义一个方法,能遍历所有类型的ArrayList集合 分析: 这时候我们不知道ArrayList集合使用什么数据类型, 可以使用泛型的通配符 ? 来接受数据类型 */ public class DemoGeneric01 { public static void main(String[] args) { ArrayList<Integer> listA = new ArrayList<>(); listA.add(10); listA.add(20); ArrayList<String> listB = new ArrayList<>(); listB.add("马尔扎哈"); listB.add("格利纳扎"); printArray(listA); printArray(listB); } public static void printArray(ArrayList<?> list){ Iterator<?> it = list.iterator(); while (it.hasNext()){ Object o = it.next(); System.out.println(o); } } }
通配符的高级使用—泛型受限泛型的上限:
泛型的下限:
4. 综合案例:斗地主(单列集合)/* 题目: 使用单列集合实现斗地主 分析: 1. 准备牌 创建一个集合poker用来存储54张牌 准备两个数组,分别存储花色和编号 两个for循环放入集合poker当中 2. 洗牌 调用Collections工具类中的shuffle()方法随机打乱牌 3. 发牌 用四个集合分别存储玩家A、B、C和底牌hand 使用索引 i % 3来进行对玩家分牌,当i >= 51时,给底牌 4. 看牌 输出四个集合存储的牌 */ import java.util.ArrayList; import java.util.Collections; public class PokerGame { public static void main(String[] args) { // 准备牌 ArrayList<String> poker = new ArrayList<>(); String[] colors = {"?","?","?"}; String[] numbers = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"}; poker.add("大王"); poker.add("小王"); for (String color : colors) { for (String number : numbers) { poker.add(color + number); } } // System.out.println(poker); // System.out.println(poker.size()); // 洗牌 Collections.shuffle(poker); // 准备存储玩家的牌 ArrayList<String> playA = new ArrayList<>(); ArrayList<String> playB = new ArrayList<>(); ArrayList<String> playC = new ArrayList<>(); ArrayList<String> hand = new ArrayList<>(); // 发牌 for (int i = 0; i < poker.size(); i++) { String o = poker.get(i); int j = i % 3; if (i >= 51){ hand.add(o); }else if (j == 0){ playA.add(o); }else if (j == 1){ playB.add(o); }else if (j == 2){ playC.add(o); } } // 看牌 System.out.println("选手A:" + playA); System.out.println("选手B:" + playB); System.out.println("选手C:" + playC); System.out.println("底牌:" + hand); } } 5. List集合
List接口的特点:
List接口中带索引的方法(特有):
6. List的实现类1. ArrayList集合
2. LinkList集合
添加方法:
得到方法:
删除方法:
判断列表是否为空:
3. Vector集合
7. Set集合
Set接口的特点:
HashSet集合的特点:
public class DemoSet { public static void main(String[] args) { Set<Integer> set = new HashSet<>(); set.add(10); set.add(20); set.add(30); set.add(20); System.out.println(set); // [20,10,30] Iterator<Integer> it = set.iterator(); while (it.hasNext()){ Integer next = it.next(); System.out.println(next); } System.out.println("============"); for (Integer i : set) { System.out.println(i); } } } 哈希值
// 巧了,"通话"和"重地"的哈希码值一样 System.out.println("重地".hashCode()); // 1179395 System.out.println("通话".hashCode()); // 1179395 HashSet存储数据的结构(哈希表)
在JDK 1.8之前,哈希表底层采用数组 + 链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK 1.8中,哈希表存储采用 数组 + 链表 + 红黑树实现,当链表长度超过阈值(8)时,将链表装换为红黑树,这样大大减少了查找时间。
Set集合存储不重复元素的原理使用add方法添加元素的时候,add方法会调用元素的hashCode方法和equals方法,判断元素是否重复。
HashSet存储自定义类型的元素
@Override public boolean equals(Object o) { if (this == o) return true; // 使用反射技术判断 o 是否是Person类型 等效于 o instanceof Person if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name,person.name); } @Override public int hashCode() { return Objects.hash(name,age); } // ============================= HashSet<Person> set = new HashSet<>(); Person one = new Person("小美女",19); Person two = new Person("小美女",19); Person three = new Person("大美女",20); System.out.println(one == two); // false System.out.println("one hashCoe:" + one.hashCode()); // one hashCoe:734175840 System.out.println("two hashCode:" + two.hashCode()); // two hashCode:734175840 set.add(one); set.add(three); set.add(two); System.out.println(set); // [Person{name='小美女',age=19},Person{name='大美女',age=20}] LinkedHashSet集合
可变参数在JDK 1.5之后,如果我们定义一个方法需要接受多个参数,,并且参数的类型一致,我们可以使用可变参数。=
修饰符 返回值类型 函数名称(参数类型...参数名称){ // 函数体 } 其实这个写法完全等价于 修饰符 返回值类型 函数名称(参数类型[]参数名称){ // 函数体 } 只是后面这种定义,在调用时必须传递数组,而前者可以直接传递数据即可。
8. Collections工具类
Comparable与Comparator的区别: Collections.sort(listB,new Comparator<Integer>() { @Override public int compare(Integer o1,Integer o2) { return o1 - o2; } }); 9. Map集合(双列集合)
概述
Map集合的特点:
Map常用子类HashMap集合的特点:
LinkedHashMap集合的特点:
Map接口中的常用方法
1. Map集合的第一种遍历方式:通过键找值的方式。import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; /* 1. public V put(K key,V value) 2. public V remove(Object key) 3. public V get(Object key) 4. public boolean containsKey(Object key) */ public class DemoMap { public static void main(String[] args) { Map<String,String> map = new HashMap<>(); // put(K key,V value) String put1 = map.put("萧炎","彩鳞"); map.put("林动","欢欢"); map.put("牧尘","洛璃"); // remove(Object key) String put2 = map.remove("牧尘"); // containsKey(Object key) boolean b1 = map.containsKey("萧炎"); // V get(Object key) String put4 = map.get("林动"); // Map集合的第一种遍历方式:通过键找值 Set<String> set = map.keySet(); // 1. 使用迭代器 Iterator<String> it = set.iterator(); while (it.hasNext()){ String key = it.next(); String value = map.get(key); System.out.println(key + "=" + value); } System.out.println("================="); // 2. 使用增强for for (String key : map.keySet()) { String value = map.get(key); System.out.println(key + "=" + value); } } } 2. Map集合的第二种遍历方式:Entry对象。static interface Map.Entry<K,V> :映射项(键-值对)。 Map.Entry<K,V>:在Map接口中有一个内部接口Entry。 Map集合中的方法:
使用步骤:
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class DemoMapEntry { public static void main(String[] args) { Map<String,Integer> map = new HashMap<>(); map.put("赵丽颖",168); map.put("冯宝宝",173); map.put("高圆圆",178); map.put("林志玲",180); System.out.println(map); // 1. 将每一个entry对象存放到set集合中 Set<Map.Entry<String,Integer>> set = map.entrySet(); // 2. 遍历entry对象,获取每一个entry对象 // 首先获得set集合的迭代器 Iterator<Map.Entry<String,Integer>> it = set.iterator(); while (it.hasNext()) { Map.Entry<String,Integer> entry = it.next(); // 3. getKey()和getValue() String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key+ "=" + value); } System.out.println("============"); // 通过增强for实现 for (Map.Entry<String,Integer> entry : set) { String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key+"="+value); } } } HashMap存储自定义类型键值Map集合保证key是唯一的,作为key的元素,必须重写hashCode和equals方法,以保证key是唯一的。 import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; public class DemoHashMapSavePerson { public static void main(String[] args) { // key:String // value:Person HashMap<String,Person> mapA = new HashMap<>(); mapA.put("北京",new Person("聂离",19)); mapA.put("上海",new Person("陆飘",19)); mapA.put("广州",new Person("杜泽",20)); mapA.put("上海",new Person("叶紫芸",18)); // 使用keySet+增强for遍历 Set<String> setA = mapA.keySet(); for (String key : setA) { Person value = mapA.get(key); System.out.println(key + "-->" + value); } System.out.println("=================="); // key:Person // value:String HashMap<Person,String> mapB = new HashMap<>(); mapB.put(new Person("海波东",30),"冰皇"); mapB.put(new Person("雅妃",25),"金之女皇"); mapB.put(new Person("萧炎",20),"炎帝"); mapB.put(new Person("古河","丹王"); mapB.put(new Person("雅妃","女皇"); // 使用entrySet+迭代器遍历 Set<Map.Entry<Person,String>> setB = mapB.entrySet(); // 获取迭代器 Iterator<Map.Entry<Person,String>> it = setB.iterator(); while (it.hasNext()) { Map.Entry<Person,String> entry = it.next(); Person key = entry.getKey(); String value = entry.getValue(); System.out.println(key+"-->"+value); } System.out.println("===================="); // 使用增强for + enteySet for (Map.Entry<Person,String> entry : setB) { Person key = entry.getKey(); String value = entry.getValue(); System.out.println(key+"-->"+value); } } } LinkedHashMap集合
Hashtable集合
Hashtable:底层也是一个哈希表,是一个线程安全的集合,是单线程集合,访问速度慢。 HashMap集合(之前学的所有集合):可以存储null值,null键 Hashtable和Vector集合一样,在JDK1.2之后被更先进的集合(HashMap、ArrayList)替代。 练习import java.util.HashMap; import java.util.Scanner; /* 题目要求: 输入一个字符串,判断其中每个字符出现的次数? 分析: 1. 使用Scanner类中的next方法,接受键盘输入的字符串 2. 创建Map集合, 其中字符作为key,字符出现的次数作为value 3. 遍历字符串,取出每一个字符 4. 使用获取到的字符,去Map集合判断key是否存在 key存在 通过key(字符)获取value(次数) value++ put(key,value),更新value的值 key不存在 put(key,1) 5. 遍历Map集合,输出结果 遍历字符串的两种方式: 1. 使用String的toCharArray()方法,将字符串变成字符数组,循环遍历 2. 使用String的length()方法和charAt(int index):获取每个索引处的单个字符,来遍历 */ public class DempMapPractise { public static void main(String[] args) { System.out.println("请输入一个字符串:"); // 使用Scanner类中的next方法 Scanner sc = new Scanner(System.in); String str = sc.next(); // 创建HashMap集合,存储字符和相应的次数 HashMap<Character,Integer> map = new HashMap<>(); // 遍历字符串,方法1: /*for (char c : str.toCharArray()){ // 如果map中包含c if (map.containsKey(c)){ Integer value = map.get(c); value++; map.put(c,value); }else{ // 如果不包含c map.put(c,1); } }*/ // 遍历字符串,方法2: for (int i = 0; i < str.length(); i++){ char c = str.charAt(i); if (map.containsKey(c)){ Integer value = map.get(c); value++; map.put(c,value); }else { map.put(c,1); } } // 遍历map集合,打印结果 for (Character key : map.keySet()) { Integer value = map.get(key); System.out.println(key + "=" + value); } // System.out.println(map); } } JDK9对集合添加的优化JDK9的新特性:
示例: import java.util.List; import java.util.Map; import java.util.Set; public class DemoStaticMehodof { public static void main(String[] args) { List<String> list = List.of("a","b","c","d"); System.out.println(list); // list.add("r"); // UnsupportedOperationException:不支持操作异常 // System.out.println(list.remove("a"));// UnsupportedOperationException // Set<String> set = Set.of("a","a","c"); // System.out.println(set); // IllegalArgumentException:非法参数异常 // IllegalArgumentException:非法参数异常,有重复元素 // Map<String,Integer> map = Map.of("聂离",20,"聂离",21,"杜泽",22); // System.out.println(map); } } 10. 综合案例:斗地主(双列集合)import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; /* 1. 准备牌 2. 洗牌 3. 发牌 4. 排序 5. 看牌 */ public class PokerGamePlus { public static void main(String[] args) { // 用来存储扑克的编号和 54张扑克 HashMap<Integer,String> poker = new HashMap<>(); // 扑克的编号 ArrayList<Integer> pokerIndex = new ArrayList<>(); // 先把大王小王及其编号存储进扑克 poker.put(0,"大王"); pokerIndex.add(0); poker.put(1,"小王"); pokerIndex.add(1); // 两个集合分别存储花色和编号 String[] colors = {"?","3"}; int index = 2; for (String number : numbers) { for (String color : colors) { poker.put(index,color + number); pokerIndex.add(index); index++; } } // System.out.println(poker); // 2. 洗牌 Collections.shuffle(pokerIndex); // System.out.println(pokerIndex); // 3. 发牌 // 3个玩家 + 1个底牌 ArrayList<Integer> playerA = new ArrayList<>(); ArrayList<Integer> playerB = new ArrayList<>(); ArrayList<Integer> playerC = new ArrayList<>(); ArrayList<Integer> hand = new ArrayList<>(); for (int i = 0; i < pokerIndex.size(); i++) { Integer in = pokerIndex.get(i); int j = i % 3; if (i >= 51) { hand.add(in); } else if (j == 0) { playerA.add(in); } else if (j == 1) { playerB.add(in); } else if (j == 2) { playerC.add(in); } } // 4. 排序,默认为从小到大 Collections.sort(playerA); Collections.sort(playerB); Collections.sort(playerC); Collections.sort(hand); // 5. 发牌 seePoker("周润发",playerA,poker); seePoker("刘德华",playerB,poker); seePoker("周星驰",playerC,poker); seePoker("底牌",hand,poker); } public static void seePoker(String name,ArrayList<Integer> keys,HashMap<Integer,String> poker) { System.out.print(name + ":"); for (Integer key : keys) { String value = poker.get(key); System.out.print(value + " "); } System.out.println(); } } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |