文章目录
- 一. 集合简单介绍
- 二. 单列集合
- 三. 双列集合
一. 集合简单介绍
- 简单介绍:集合和数组一样都相当于是一个容器,但集合可以自动扩容。集合和数组的对比:
(1)数组的长度是固定的,集合的长度是可变的;
(2)数组可以存储基本数据类型和引用数据类型;集合可以存储引用数据类型,不能直接存储基本数据类型,需要先将基本数据类型转为其对应的包装类。基本数据类型对应的包装类:byte–Byte、short–Short、char–Character、int–Integer、long–Long、float–Float、double–Double、boolean–Boolean。 - java中规定了很多种集合,例如:TreeSet、HashSet、HashMap、Vector、Collection、Map、LinkedHashSet、LinkedList和ArrayList等等。我们可以将集合大致上分为两大类:Collection集合、Map集合。其中,Collection属于单列集合;Map属于双列集合。所谓单列集合就是在添加数据的时候每次只能添加一个元素;所谓双列集合就是在添加数据的时候每次只能添加一对元素(两个元素–键值对,和python字典类似)。
其实后面使用次数最多的就是HashMap和ArrayList
。
二. 单列集合
- 有图有真相
关于Collection的代码如下:
// Collection是一个接口,我们不能直接创建它的对象,只能创建它的实现类对象.
Collection<String> collection = new ArrayList<>(); //通过多态的方式去创建Collection的对象
// 添加元素
collection.add("aaa");
collection.add("bbb");
collection.add("ccc");
System.out.println(collection);
// 删除元素:因为Collection里面定义的是共性的方法(List系列和Set系列,Set系列没有索引),不能通过索引删除元素,
// 只能通过元素的对象进行删除。
collection.remove("ccc");
System.out.println(collection);
// 判断集合中是否包含元素
System.out.println(collection.contains("aaa"));
// 清空元素
collection.clear();
System.out.println(collection);
// 判断集合是否为空
System.out.println(collection.size());
System.out.println(collection.isEmpty());
/*
输出:
[aaa, bbb, ccc]
[aaa, bbb]
true
[]
0
true
*/
- Collection集合的遍历:迭代器遍历、增强for遍历、Lambda表达式遍历。
*(1) 迭代器遍历:迭代器在java中的类是Iterator,迭代器是集合专用的遍历方式。我们可以通过一个方法(iterator())获取迭代器对象,默认指向当前集合的0索引;然后利用hasNext() 和 next 获取集合中每一个元素。迭代器不依赖索引。用代码解释迭代器:
// 迭代器代码解释:
Iterator<String> it = list.iterator();
boolean flag = it.hasNext();
// 通过hasNext()方法判断集合中是否存在元素(相当于创建了一个指针),存在返回true,不存在返回false.
String str = it.next(); // next()做了两件事情:获取元素,并移动指针(也就是往后移动)
System.out.println(str); //打印输出
/* 迭代器的注意细节:
(1)迭代器遍历完成,指针不会复位,也就说遍历完成迭代器的指针指向最后没有元素的位置.如果我们想要继续二次遍历集合,只能再次获取一个新的迭代器对象;
(2)循环中只能使用一次next()方法;
(3)迭代器遍历时(也就是遍历过程中),不能使用集合的方法进行添加或者删除元素.
*/
迭代器遍历Collection集合代码如下:
// 创建集合并添加元素
Collection<String> collection = new ArrayList<>();
collection.add("aaa");
collection.add("bbb");
collection.add("ccc");
// 获取集合collection的迭代器对象,默认指向集合collection的0索引.
Iterator<String> it = collection.iterator();
while(it.hasNext()){ //如果集合有元素,it.hasNext()返回true,不存在元素返回false.
String str = it.next(); // next()方法先获取元素,然后让指针往后移动.
System.out.println(str);
}
// 产生一个新的迭代器对象.
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
iterator.remove(); //通过迭代器删除元素
}
System.out.println(collection);
System.out.println(collection.size());
/*
输出:
aaa
bbb
ccc
aaa
bbb
ccc
[]
0
*/
- (2)增强for遍历
增强for遍历:增强for遍历的底层就是迭代器,为了简化迭代器代码书写。增强for遍历是在JDK5之后出现的,其内部原理就是一个Iterator迭代器;所有的单列集合和数组才能使用增强for进行遍历。
// 增强for遍历的格式
// for(元素的数据类型 变量名: 数组或者集合){
//
// }
// 创建集合并添加元素
Collection<String> collection = new ArrayList<>();
collection.add("aaa");
collection.add("bbb");
collection.add("ccc");
// 增强for遍历,这里的s只是一个第三方变量.
for (String s : collection) {
System.out.println(s);
}
/*
输出:
aaa
bbb
ccc
*/
- (3)时间紧任务重,所以Lambda表达式遍历(别看了,开始摆烂把。哈哈哈,这种方式先别看了,以后用到再说吧)
- List接口继承Collection接口,ArrayList类、LinkedList类、Vector类实现了List接口。由于List是一个接口,所以我们不能直接创建它的对象,只能创建它的实现类对象。关于ArrayList类、LinkedList类、Vector类的具体用法大家可以自行网上查一下。同理:Set集合和List集合级别一样都是接口,都存在对应的实现类。
- 泛型
- 泛型是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。泛型中不能写基本数据类型,只能写引用数据类型,如果不写泛型类型,类型默认是Object。泛型的好处:统一数据类型;把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能确定下来。
- 泛型的三种使用方式:泛型类、泛型方法、泛型接口。
- (1)泛型类的定义格式:
修饰符 class 类名<泛型类型>{}
例子:public class ArrayList<E>
这里的E表示不确定类型;当我们使用ArrayList类创建对象时,E的类型就确定了。换句话说这里的E可以理解为变量,但不是用来记录数据的,而是记录数据类型的。 - (2)泛型方法的定义格式:
修饰符 <泛型类型> 返回值类型 方法名(泛型类型 变量名){}
例子:public <E> void show(E e){}
。此处的E可以理解为变量,但不是用来记录数据的,而是记录类型的。调用该方法show()时,E的类型就确定了。 - (3)泛型接口的定义格式:
修饰符 interface 接口名<泛型类型>{}
例子:public interface List<E>{}
。泛型接口的使用,方式1:实现类给出具体类型;方式2:实现类延续泛型,创建对象时再确定。 - 泛型不具备继承性,但是数据具备继承性(使用下面代码理解)。泛型的应用场景:我们在定义类、方法、接口时,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。如果类型不确定,但是知道以后只能传递某个继承体系,就可以使用泛型的通配符
< ? >
。 - 定义泛型的时候使用A-Z中任何一个字母都可以,但是为了规范,大家约定俗成的把泛型字母定义如下
泛型字母 | 作用 |
E(Element) | 表示集合中元素的类型 |
T(Type) | 通常用于表示类或方法的泛型类型 |
K(Key) | 键 |
V(Value) | 值 |
N(Number) | 数值类型 |
public class Test {
public static void main(String[] args) {
// 泛型不具备继承性,但是数据具备继承性
ArrayList<Ye> listYe = new ArrayList<>();
ArrayList<Fu> listFu = new ArrayList<>();
ArrayList<Zi> listZi = new ArrayList<>();
show(listYe);
//show(listFu); // 会报错. 这是因为泛型不具备继承性,你在show()方法的泛型里面写的什么类型,就只能传递什么类型的数据.
//show(listFu); // 会报错 你写的Ye这个类,因此只能传递Ye这个类创建的ArrayList集合对象listYe,子类的不能传递
listYe.add(new Ye());
listYe.add(new Fu());
listYe.add(new Zi()); //你可以往集合listYe里面添加Fu类的对象、Zi类的对象,这表明数据具备继承性.
}
public static void show(ArrayList<Ye> list){
}
}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
public class Test {
public static void main(String[] args) {
// 泛型不具备继承性,但是数据具备继承性
ArrayList<Ye> listYe = new ArrayList<>();
ArrayList<Fu> listFu = new ArrayList<>();
ArrayList<Zi> listZi = new ArrayList<>();
ArrayList<Student> listStu = new ArrayList<>();
show(listYe);
show(listFu);
// show(listZi);
// show(listStu);
/*
将show()方法的泛型Ye修改为E代码不会报错.但是此时show(listStu);也不会报错,(我们的出发点只是将存在继承关系的
listYe、listFu、listZi放入到show方法中,根本不想让listStu调用成功.) 此时我们可以使用泛型的通配符"?",
"?"也表示不确定的类型,使用方式有两种: ? extends E--表示可以传递E或者E所有的子类类型;
? super E--表示可以传递E或者E所有的父类类型.
}
*/
// public static <E> void show(ArrayList<E> list){
// }
// public static void show(ArrayList<? extends Ye> list){
// // show(listStu);会报错.因为此时我们限定只能是Ye或者Ye的所有子类可以调用show方法.
// }
public static void show(ArrayList<? super Fu> list){
// show(listStu);show(listZi); 会报错.因为此时我们限定只能是Fu类或者Fu的所有父类可以调用show方法.
}
}
class Student{}
class Ye{}
class Fu extends Ye{}
class Zi extends Fu{}
- 单列集合Collection使用场景总结
三. 双列集合
- 简单介绍
Map集合属于双列集合。双列集合的特点:(1)双列集合一次需要添加一对数据(两个元素),分别是键和值;(2)键不能重复,值可以重复;(3)键和值是一一对应的,每个键只能找到自己对应的值;(4)“键”+“值"这个整体我们称为"键值对"或者"键值对对象”,在java中叫做"Entry对象"。
// Map是一个接口,接口是不能创建对象的,因此只能通过Map的实现类创建对象.
Map<String,String> map = new HashMap<>();
// 使用put()方法添加元素. 在添加数据时,如果键不存在,那么直接把键值对对象添加到map集合中,
// 在添加数据时,如果键是存在的,那么就会把原有的键值对对象覆盖,会把被覆盖的值(旧值)进行返回.
map.put("郭靖","黄蓉");
map.put("杨过","小龙女");
map.put("令狐冲","东方不败");
System.out.println(map);
String str = map.put("令狐冲", "任盈盈");
System.out.println(str);
System.out.println(map);
// 使用remove()方法删除元素. 返回键对应的值
String s = map.remove("郭靖");
System.out.println(s);
System.out.println(map);
System.out.println(map.containsKey("杨过"));
System.out.println(map.containsKey("郭靖"));
System.out.println(map.containsValue("小龙女"));
System.out.println(map.containsValue("黄蓉"));
/*
输出:
{令狐冲=东方不败, 杨过=小龙女, 郭靖=黄蓉}
东方不败
{令狐冲=任盈盈, 杨过=小龙女, 郭靖=黄蓉}
黄蓉
{令狐冲=任盈盈, 杨过=小龙女}
true
false
true
false
*/
- Map集合的遍历方式:键找值、键值对、Lambda表达式。
// Map是一个接口,接口是不能创建对象的,因此只能通过Map的实现类创建对象.
Map<String,String> map = new HashMap<>();
map.put("郭靖","黄蓉");
map.put("杨过","小龙女");
map.put("令狐冲","东方不败");
System.out.println(map);
// 1. 键找值
// 先通过keySet()获取所有的键,把这些键放到一个单列集合set中
// 2.增强for遍历
Set<String> set = map.keySet();
for (String key : set) {
System.out.println(key+"="+map.get(key));
}
// 2.迭代器遍历
// Iterator<String> iterator = set.iterator();
// while(iterator.hasNext()){
// String key = iterator.next();
// System.out.println(key+"="+map.get(key));
// }
// 键值对
// 通过entrySet()获取所有的键值对对象,返回一个Set集合
// 2.增强for遍历
Set<Map.Entry<String, String>> entry = map.entrySet(); //Set<Map.Entry<String, String>>泛型嵌套
for (Map.Entry<String, String> entries : entry) {
String key = entries.getKey();
String value = entries.getValue();
System.out.println(key+"="+value);
}
//2.迭代器遍历
// Iterator<Map.Entry<String, String>> it = entry.iterator();
// while(it.hasNext()){
// Map.Entry<String, String> next = it.next();
// System.out.println(next.getKey()+"="+next.getValue());
// }
/*
输出:
{令狐冲=东方不败, 杨过=小龙女, 郭靖=黄蓉}
令狐冲=东方不败
杨过=小龙女
郭靖=黄蓉
令狐冲=东方不败
杨过=小龙女
郭靖=黄蓉
*/