集合:是一个大小可变的容器。
集合与数组的区别:
数组的长度是定义出来就固定的,数组的存储的数据类型也固定了。
集合的大小可变,可以存储任意类型的数据。
容器中的数据也称为元素。
开发中:集合用的更多。原因是集合的大小可变,开发中的数据通常是变化的。
Java中集合的代表是Collection。
Java中集合的体系结构:
集合不只有一种,集合有很多个,每个集合的功能是存在差异的。
Collection<E>(接口,不能直接使用)
/ \
Set<E>(接口) List<E>(接口)
/ / \
HashSet<E>(实现类) ArrayList<E>(实现类) LinkedList<E>(实现类)
/
LinkedHashSet<E>(实现类)
Collection体系集合的特点:
Set系列集合的特点:添加的元素是无序,不重复的,无索引。
Set集合无序的根本原因就是用了哈希表存储元素
-- HashSet:添加的元素是无序不重复的无索引。
-- LinkedHashSet:添加的元素是有序不重复的。
List系列集合的特点: 添加的元素是有序,可重复,有索引。
-- ArrayList: 添加的元素是有序,可重复,有索引。
-- LinkedList: 添加的元素是有序,可重复,有索引。
Collections工具类的使用:
Arrays不是数组,是操作数组的
Collections不是集合,是操作集合的。
工具类的方法基本上都是静态的。
Collections静态方法:
(1)public static <T> boolean addAll(Collection<T> c , T... elements)
给集合添加元素。
支持所有集合的。
参数一:支持所有集合
参数二:支持加入可变参数的数据。
(2)public static void shuffle(List<?> list)
将集合中的元素乱序。
参数:是一个List集合
这个方法只能支持List集合
(3)public static <T> void sort(List<T> list)
将集合中的元素排序,默认是升序排序
参数:是一个List集合
这个方法只能支持List集合的排序
排序:大小顺序。
有序:添加顺序。
(4)public static <T> void sort(List<T> list, Comparator<? super T> c)
参数一:需要被排序的集合
参数二:自定义比较规则对象:比较器。
注意:对于数值类型的集合sort方法可以直接自动的升序排序。
对于引用数据类型,sort不能排序,原因是人家根本不清楚大小规则。
public class CollectionsDemo02 {
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
apples.add(new Apple("红富士1","红色",502.29));
apples.add(new Apple("红富士2","粉红",602.29));
apples.add(new Apple("水晶","绿色",303.8));
// Collections集合默认不能为对象排序的,原因是人家根本不清楚大小规则。
// Collections.sort(apples);
// Collections集合提供了一个排序方法。
// (4)public static <T> void sort(List<T> list, Comparator<? super T> c)
// 我们认为应该按照重量比较。
Collections.sort(apples, new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
// 比较方法:
// 默认会自动提取集合中的两个两个对象,拿来给程序员自己比较
// 如果程序员认为o1比o2大应该返回一个正整数即可。
// 如果程序员认为o1比o2小应该返回一个负整数即可。
// 如果程序员认为o1等于o2应该返回0。
// o1 = a1
// o2 = a2
if(o1.getWeight() > o2.getWeight()){
return 1 ; // 大于
}else if(o1.getWeight() < o2.getWeight()){
return -1 ; // 小于
}
return 0; // 相等了
}
});
System.out.println(apples);
}
}
List<String> lists1 = new ArrayList<>();
Collections.addAll(lists1,"张三","李四","王五","王麻子");
Collections.shuffle(lists1); // 打乱顺序 :洗牌
System.out.println(lists1);
List<Integer> lists2 = new ArrayList<>();
lists2.add(12);
lists2.add(12);
lists2.add(5);
lists2.add(19);
lists2.add(19);
lists2.add(111);
lists2.add(89);
Collections.sort(lists2); // 排序!
System.out.println(lists2);
LinkedList集合:
底层是双链表结构,”查询慢“,”增删快“,线程不安全的,效率高
有序(存取顺序一致),有索引,元素可重复
LinkedList集合是可以用来设计队列和栈的。
如果需要执行大量的增删操作,则选择LinkedList。
如果不需要执行增删操作,而存在查询操作,则选择ArrayList
LinkedList集合特有方法方法:
因为双链表结构,首尾元素是可以直接定位的。
所以LinkedList集合操作首位元素的性能极好,所以
LinkedList集合提供了很多的首位操作的API:
public void addFirst(E e): 将元素添加到链表头
public void addLast(E e): 将元素添加到链表尾部
public E getFirst(): 获得链表头元素
public E getLast(): 获得链表尾部元素
public E removeFirst(): 删除链表头元素
public E removeLast(): 删除链表尾部元素
LinkedList集合是可以用来设计队列和栈的。
1,// 添加的元素是有序,可重复,有索引。
Collection lists = new ArrayList();
lists.add("java1");
lists.add("java1");
lists.add("java2");
lists.add("java2");
System.out.println(lists);
打印 [java1, java1, java2, java2]
2,// HashSet : 添加的元素是无序,不重复的,无索引。
Collection c = new HashSet();
c.add("xiaoPang");
c.add("Java");
c.add("Java");
c.add("JavaEE");
c.add("JavaEE");
c.add("Oracle");
System.out.println(c);
打印 [Java, JavaEE, xiaoPang, Oracle]
Collection接口是全部集合的父类。Collection集合的功能是所有集合通用的。
Collection集合的常用API有哪些呢?
public boolean add(E e)`: 把给定的对象添加到当前集合中 。
public void clear()` :清空集合中所有的元素。
public boolean remove(E e)`: 把给定的对象在当前集合中删除。
public boolean contains(Object obj)`: 判断当前集合中是否包含给定的对象。
public boolean isEmpty()`: 判断当前集合是否为空。
public int size()`: 返回集合中元素的个数。
public Object[] toArray()`: 把集合中的元素,存储到数组中
Collection c1 = new ArrayList();
/ 获取集合元素的大小!
System.out.println(c1.size());
// 把集合转换成数组:集合一旦元素确定了就可以转成数组。
Object[] arrs = c1.toArray();
System.out.println("数组:"+Arrays.toString(arrs));
Collection集合的遍历:
有三种的:
(1)foreach遍历是可以的。
for(被遍历集合或者数组中元素的类型 变量 : 被遍历集合或者数组){
}
(2)迭代器
(3)JDK 1.8之后的新技术
Collection<String> c = new ArrayList<>();
c.add("JavaEE");
c.add("Oracle");
c.add("Mysql");
c.add("Redis");
System.out.println(c);
// JDK 1.8之后的新技术(暂时了解): Lambda表达式遍历集合。
c.forEach( s -> {
System.out.println(s);
});
System.out.println("-------------");
c.forEach( s -> System.out.println(s) );
System.out.println("-------------");
c.forEach(System.out::println );
泛型在集合中的使用。
泛型的概念:是用于约束某个类只能操作某个数据类型。
泛型的格式: <数据类型> ,泛型可以理解成标记。
Collection集合是全部支持泛型的。
泛型中的数据类型只能是引用数据类型。集合也只能支持引用数据类型。
不能填写int byte而应该是Integer , Byte
泛型好处:可读性好,约定集合只能存储某个类型,避免数据类型转换异常ClassCastException。
1.集合使用了什么泛型就只能支持什么数据类型。
2.JDK 1.7之后泛型后面是不用申明数据类型的
Collection<String> c = new ArrayList<String>();
Collection<String> c = new ArrayList<>();
定义泛型方法。
需求: 随便给你一个数组,就能输出这个数组的元素内容。
泛型方法的格式:
修饰符 <泛型变量> 返回值类型 方法名称(形参){
}
要求:必须使用<泛型变量>申明。
前后的泛型变量必须一致!
public class FanXingDemo01 {
public static void main(String[] args) {
Integer[] arrs = new Integer[]{10,20,30,40};
String[] names = new String[]{"李开义","李童洲","李锰"};
Double[] scores = new Double[]{19.2,22.3 ,33.2};
printArr(arrs);
printArr(names);
printArr(scores);
}
public static <T> void printArr(T[] arrs){
StringBuilder sb = new StringBuilder();
sb.append("[");
// 直接遍历数组输出元素的内容
for(int i = 0 ; i < arrs.length ; i++){
T ele = arrs[i];
sb.append(i==arrs.length -1 ? ele : ele+",");
/* if(i == arrs.length -1){
sb.append(ele);
}else{
sb.append(ele+",");
}*/
}
sb.append("]");
System.out.println(sb);
}
}
泛型接口和使用。
泛型接口的定义: 用了泛型的接口就是泛型接口。
泛型接口的定义格式:
修饰符 接口名称<泛型变量>{}
class SavaClazz implements Save<Clazz>{
@Override
public void add(Clazz stu) {
}
}
class SaveStudent implements Save<Student>{
@Override
public void add(Student stu) {
}
}
class SavaAnimal implements Save<Animal>{
@Override
public void add(Animal stu) {
}
}
// 公司的规范:保存数据
interface Save<E>{
void add(E stu);
}
class Student{
}
class Clazz{
}
class Animal{
}
泛型的通配符。
需求:开发一个极品飞车的游戏。
可能有很多车,每种车可以一起参数比赛。
注意:
虽然Jeep 继承了 Car
但是Collection<Jeep>泛型类型和Collection<Car>泛型没有继承关系。
通配符:就是? 可以在泛型使用数据类型的时候代表一切类型。
泛型的上下限:可以约束?是什么要求
? extends Car : 泛型的上限?必须是Car或者子类。
? super Car : 泛型的下限?必须是Car或者父类。(不会用)
public class GameDemo01 {
public static void main(String[] args) {
// 创建几部车。
Collection<BMW> bmws = new ArrayList<>();
bmws.add(new BMW());
bmws.add(new BMW());
bmws.add(new BMW());
start(bmws);
Collection<JEEP> jeeps = new ArrayList<>();
jeeps.add(new JEEP());
jeeps.add(new JEEP());
start(jeeps);
// Collection<Dog> dogs = new ArrayList<>();
// dogs.add(new Dog());
// dogs.add(new Dog());
// start(dogs);
}
// 写一个比赛的方法
public static void start(Collection<? extends Car> cars){
}
}
class Dog{
}
// 汽车:父类。
class Car{
}
class BMW extends Car{
}
class JEEP extends Car{
}
Map集合的概述。
什么是Map集合?Map集合也是一个容器。与Collection集合是没有关系的, 他们属于两个不同的集合体系。
Map集合称为键值对集合,Map集合中的每个元素是有两个值组成的
Map集合的每个元素的格式是:“键=值” 有时候我们称键是key , 值是value.
所以Map集合的元素格式是:
{key1=value1 , key2=value2 , key3=value3 , ...}
小结:有人把Map集合称为双列即可,而Collection集合称为单列集合。
为什么要使用Map集合呢?
原因1:
Map集合的信息描述更加的具体和直观。
需求:存储一个学生的信息(徐干,21 ,男,101期就业班级)。
Collection存储: [徐干,21 ,男,101期就业班级]
Map集合存储: {姓名=徐干,年龄=21,性别=男,班级=101期就业班级}
原因2:
场景:需要开发一个购物车系统。
购物车中的信息可以采用Map集合存储:
Map集合的格式:
{iphonex=100 , iphoneXMax=1 , Apple=100}
总结:对于信息需要很具体化,或者类似购物车这样的业务,使用Map集合存储数据
会更加的合适。
Map集合也存在自己的体系结构。
Map是Map集合的根类。
Map<K,V>:接口 , K - 此映射所维护的键的类型 , V - 映射值的类型
/
HashMap<K,V>: 实现类。可以使用的。
/
LinkedHashMap<K,V>: 实现类。可以使用的。
Map集合体系结构的特点:
Map系列集合:元素是无序,键是不重复的,值是不做要求的。
键值对都可以为null。
HashMap实现类的特点:元素是无序,键是不重复的,值是不做要求的。
键值对都可以为null。
LinkedHashMap实现类的特点:元素是有序,键是不重复的,值是不做要求的。
键值对都可以为null。
小结:
1.Map集合的元素是无序的,键是不重复的,值是不做要求的。
2.如果键重复了,后面键对应的整个元素会覆盖前面重复键对应的整个元素。
3.Map集合的元素值是不做要求的。
4.Map集合的键值对都可以为null。
5.Map集合的键是什么类型,值是什么类型,添加的元素就必须是这些类型。
Map集合的常用方法(API):
- `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 boolean containKey(Object key)`:判断该集合中是否有此键。
小结:
1.这些API很重要必须记住(理解记忆)
2.这些API在以后的开发中用的很多!!
Map集合的遍历:
Map集合的遍历是只一个一个元素的取出来(此时包含了每个元素的键和值)。
Map集合的遍历有3种方式:
方式一: 键找值,根据先获取Map集合的全部键,再来找到全部的值。
public class MapDemo01 {
public static void main(String[] args) {
// 1.创建一个Map集合对象。
Map<String,String> maps = new HashMap<>();
maps.put("徐干","广州");
maps.put("孙悟空","花果山");
maps.put("蜘蛛精","盘丝洞");
// 2.通过调用Map集合的keySet()方法,提取Map集合的全部键,
// 是放到一个Set集和
Set<String> keys = maps.keySet();
//System.out.println(keys);
// 3.遍历Map集合的全部键。
for(String key : keys){
// 4.根据每个键调用get(K key)来获取对应的值。
String value = maps.get(key);
System.out.println(key+"="+value);
}
}
}
方式一的遍历:
键找值,根据先获取Map集合的全部键,再来找到全部的值。
步骤:
1.创建一个Map集合对象。
2.通过调用Map集合的keySet()方法,提取Map集合的全部键,是放到一个Set集合。
3.遍历Map集合的全部键。
4.根据每个键调用get(K key)来获取对应的值。
小结:
这种方式实际上是比较简单的,建议大家使用。
方法二:键值对方法来遍历。
public class MapDemo02 {
public static void main(String[] args) {
// 1.创建一个Map集合对象。
Map<String,String> maps = new HashMap<>();
maps.put("徐干","广州");
maps.put("孙悟空","花果山");
maps.put("蜘蛛精","盘丝洞");
System.out.println(maps);
// maps = { 蜘蛛精=盘丝洞 , 孙悟空=花果山 , 徐干=广州}
//
// 使用一种foreach遍历的形式。
/**
* foreach格式:
* for(被遍历集合或者数组中元素的类型 变量名称 : 被遍历集合或者数组){
*
* }
*
* 如果直接对Map集合使用foreach遍历,我们是不清楚Map集合元素(key=value)的类型的。
* Map集合是不能直接用foreach来遍历的。
*
* 所以Java提供了一个方法:Set<Map.Entry<K,V>> entrySet()
* 可以把Map集合转换成一个Set集合
* sets = [ (蜘蛛精=盘丝洞) , (孙悟空=花果山) , (徐干=广州) ]
* entry
* 此时这个元素:(蜘蛛精=盘丝洞)就有类型:Map.Entry<String,String>
*
*/
Set<Map.Entry<String,String>> sets = maps.entrySet();
for(Map.Entry<String,String> entry : sets){
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
}
}
Map集合的遍历方式二:
键值对方式来遍历。
是一种foreach遍历的形式。
Java提供了一个方法:Set<Map.Entry<K,V>> entrySet()
可以把Map集合转换成一个Set集合
sets = [ (蜘蛛精=盘丝洞) , (孙悟空=花果山) , (徐干=广州) ]
entry
此时这个元素:(蜘蛛精=盘丝洞)就有类型:Map.Entry<String,String>
小结:
方式二相对较复杂,大家可以选用!!
方法三:JDK1.8之后的新技术来遍历(Lambda表达式,现在了解即可)
public class MapDemo03 {
public static void main(String[] args) {
Map<String,String> maps = new HashMap<>();
maps.put("徐干","广州");
maps.put("孙悟空","花果山");
maps.put("蜘蛛精","盘丝洞");
maps.forEach((k , v) -> {
System.out.println(k + "=" + v);
});
// maps.forEach((k , v) -> System.out.println(k + "=" + v));
}
}
Map集合也存在自己的体系结构。
Map是Map集合的根类。
Map<K,V>:接口 , K - 此映射所维护的键的类型 , V - 映射值的类型
/
HashMap<K,V>: 实现类。可以使用的。
/
LinkedHashMap<K,V>: 实现类。可以使用的。
Map集合体系结构的特点:
Map系列集合:元素是无序,键是不重复的,值是不做要求的。
键值对都可以为null。
HashMap实现类的特点:元素是无序,键是不重复的,值是不做要求的。
键值对都可以为null。
LinkedHashMap实现类的特点:元素是有序,键是不重复的,值是不做要求的。
键值对都可以为null。
1.LinkedHashMap实现类的特点:元素是"有序",键是不重复的,值是不做要求的。
键值对都可以为null。
LinkedHashMap使用了链表来记录每个元素的添加顺序。所以有序!
public class LinkedHashMapDemo01 {
public static void main(String[] args) {
Map<String,Integer> maps = new LinkedHashMap<>();
// 添加一些元素:put
maps.put("iphoneX",1); // 被覆盖
maps.put("iphoneX",100);
maps.put("iphoneMax",100); // 被覆盖
maps.put("iphoneMax",1);
maps.put("apple",100);
maps.put(null,null);
System.out.println(maps);
}
}