今日内容
- Collection集合------------------>必须掌握
- 单列集合继承体系
- Collection常用方法
- 迭代器------------------>必须掌握
- 迭代器的使用
- 迭代器的原理
- 增强for循环
- 泛型------------------>掌握使用泛型-----相对难点
- 定义和使用含有泛型的类
- 定义和使用含有泛型的方法
- 定义和使用含有泛型的接口
- 泛型通配符
- 数据结构--------->了解
- 常见数据结构的特点
- List集合------------------>必须掌握
- List常用方法
- List实现类的使用
第一章 Collection集合
1.1 集合概述
- 概述: 集合是java中提供的一种容器,可以用来存储多个引用数据类型的数据
- 分类:
- 单列集合: 以单个单个元素进行存储
- 双列集合: 以键值对的形式进行存储
- 集合与数组的区别:
- 长度:
- 数组长度是固定的
- 集合长度是不固定的
- 存储范围:
- 数组可以存储基本类型+引用类型 eg; int[],String[]
- 集合只能存储引用类型,如果要存储基本类型,需要存储基本类型对应的包装类类型 eg; ArrayList
,ArrayList
- 长度:
1.2 单列集合常用类的继承体系[重点]
-
单列集合: 以单个单个元素进行存储
-
单列集合继承体系:
-
Collection接口: 是所有单列集合的顶层父接口,所以Collection中定义了所有单列集合共有的方法
- List接口: 继承Collection接口,特
- 特点: 元素有索引,元素可重复,元素存取有序
- ArrayList类: 底层采用的是数组结构,查询快,增删慢
- LinkedList类: 底层采用的是链表结构,查询慢,增删快
- ...
- Set接口: 继承Collection接口,特点: 元素无索引,元素唯一(不可重复)
- HashSet类: 底层采用的是哈希表结构,由哈希表结构保证元素唯一,元素存取无序
- LinkedHashSet类:底层采用的是哈希表+链表结构,由哈希表结构保证元素唯一,由链表保证元素存取有序
- TreeSet类:底层采用的是红黑树结构,可以对元素进行排序
- ....

-
1.3 Collection 常用功能
-
Collection是接口,只能通过其子类创建对象
-
Collection是所有单列集合的顶层父接口,所以所有单列集合都拥有Collection中的方法
-
常用方法:
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(): 把集合中的元素,存储到数组中
/** * Created by PengZhiLin on 2021/8/3 9:34 */ public class Test { public static void main(String[] args) { // 创建Collection集合对象,限制集合元素的类型为String类型 Collection<String> col = new ArrayList<>(); //- `public boolean add(E e)`: 把给定的对象添加到当前集合中 。 col.add("谢霆锋"); col.add("王宝强"); col.add("贾乃亮"); col.add("陈羽凡"); // col:[谢霆锋, 王宝强, 贾乃亮, 陈羽凡] System.out.println("col:" + col); //- `public void clear()` :清空集合中所有的元素。 //col.clear(); //System.out.println("col:" + col);// col:[] //- `public boolean remove(E e)`: 把给定的对象在当前集合中删除。 // 删除王宝强 boolean res1 = col.remove("王宝强"); System.out.println("res1:"+res1);// res1:true System.out.println("col:" + col);// col:[谢霆锋, 贾乃亮, 陈羽凡] // 删除潘粤明 boolean res2 = col.remove("潘粤明"); System.out.println("res2:"+res2);// res2:false System.out.println("col:" + col);// col:[谢霆锋, 贾乃亮, 陈羽凡] //- `public boolean contains(Object obj)`: 判断当前集合中是否包含给定的对象。 // 判断是否包含王宝强这个元素 boolean res3 = col.contains("王宝强"); System.out.println("res3:"+res3);// res3: false // 判断是否包含贾乃亮这个元素 boolean res4 = col.contains("贾乃亮"); System.out.println("res4:"+res4);// res4: true //- `public boolean isEmpty()`: 判断当前集合是否为空。 boolean res5 = col.isEmpty(); System.out.println("col是否为空:"+res5);// false //- `public int size()`: 返回集合中元素的个数。 int size = col.size(); System.out.println("元素个数:"+size);// 3 //- `public Object[] toArray()`: 把集合中的元素,存储到数组中 Object[] arr = col.toArray(); System.out.println("arr:"+ Arrays.toString(arr));// arr:[谢霆锋, 贾乃亮, 陈羽凡] } }
第二章 Iterator迭代器
2.1 Iterator接口
迭代的概念
- 概述:迭代即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
- 迭代的步骤:
- 获取迭代器对象
- 使用迭代器对象判断集合中是否有元素可以取出
- 如果有元素可以取出,就直接取出来该元素,如果没有元素可以取出,就结束迭代
获取迭代器对象
Collection集合提供了一个获取迭代器的方法:
public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的。
Iterator迭代器对象的常用方法
-
public boolean hasNext():如果仍有元素可以迭代,则返回 true。 -
public E next():返回迭代的下一个元素。 -
void remove()删除当前迭代出来的元素 -
案例:
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; /** * Created by PengZhiLin on 2021/8/3 9:51 */ public class Test { public static void main(String[] args) { // 创建Collection集合对象,限制集合元素的类型为String类型 Collection<String> col = new ArrayList<>(); // 往集合中添加元素 col.add("谢霆锋"); col.add("王宝强"); col.add("贾乃亮"); col.add("陈羽凡"); // 获取迭代器 Iterator<String> it = col.iterator(); // 循环判断是否有元素可以取出来 while (it.hasNext()) { // 说明有元素可以取出来,取出来 String e = it.next(); System.out.println("取出来的元素:" + e); // 删除当前迭代出来的元素 it.remove(); } System.out.println("col:"+col);// col:[] } }
2.2 迭代器的实现原理
- 迭代器的实现原理
我们在之前案例已经完成了Iterator遍历集合的整个过程。当遍历集合时,首先通过调用集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。
Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素。在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。

2.3 迭代器的常见问题
常见问题一
-
在进行集合元素获取时,如果集合中已经没有元素可以迭代了,还继续使用迭代器的next方法,将会抛出java.util.NoSuchElementException没有集合元素异常。
/** * Created by PengZhiLin on 2021/8/3 10:02 */ public class Test1 { public static void main(String[] args) { // 创建Collection集合对象,限制集合元素的类型为String类型 Collection<String> col = new ArrayList<>(); // 往集合中添加元素 col.add("谢霆锋"); col.add("王宝强"); col.add("贾乃亮"); col.add("陈羽凡"); // 获取迭代器 Iterator<String> it = col.iterator(); // 循环判断是否有元素可以取出来 while (it.hasNext()) { // 说明有元素可以取出来,取出来 String e = it.next(); System.out.println("取出来的元素:" + e); } System.out.println("col:" + col); // 在进行集合元素获取时,如果集合中已经没有元素可以迭代了, // 还继续使用迭代器的next方法,将会抛出java.util.NoSuchElementException没有集合元素异常。 //String e = it.next();// 报NoSuchElementException没有集合元素异常。 // 解决办法: 重新获取迭代器 // 获取迭代器 Iterator<String> it1 = col.iterator(); // 循环判断是否有元素可以取出来 while (it1.hasNext()) { // 说明有元素可以取出来,取出来 String e = it1.next(); System.out.println("取出来的元素:" + e); } System.out.println("col:" + col); } } -
解决方式: 使用集合从新获取一个新的迭代器对象来使用
常见问题二
-
在进行集合元素迭代时,如果添加或移除集合中的元素 , 将无法继续迭代 , 将会抛出ConcurrentModificationException并发修改异常.
/** * Created by PengZhiLin on 2021/8/3 10:02 */ public class Test2 { public static void main(String[] args) { // 创建Collection集合对象,限制集合元素的类型为String类型 Collection<String> col = new ArrayList<>(); //Collection<String> col = new CopyOnWriteArrayList<>(); // 往集合中添加元素 col.add("谢霆锋"); col.add("王宝强"); col.add("贾乃亮"); col.add("陈羽凡"); // 获取迭代器 Iterator<String> it = col.iterator(); // 循环判断是否有元素可以取出来 while (it.hasNext()) { // 说明有元素可以取出来,取出来 String e = it.next(); System.out.println("取出来的元素:" + e); // 迭代的同时,往集合中,添加或者删除元素---->不可以的,会报ConcurrentModificationException并发修改异常 col.add("潘粤明");// 解决方式:使用CopyOnWriteArrayList集合 //col.remove(e);// --->解决方式:使用迭代器的删除方法 // 迭代器自己删除----可以的 //it.remove(); } System.out.println("col:" + col); } } -
解决办法:
- 使用CopyOnWriteArrayList集合,就可以迭代的时候,往集合中添加或删除元素
- 使用迭代器的remove方法实现一边迭代,一边删除
2.4
-
概述: 增强for循环(foreach循环),是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和Collection集合
-
原理: 内部基于Iterator迭代器实现,所以在遍历的过程中,不能对集合中的元素进行增删操作,否则抛出ConcurrentModificationException并发修改异常
-
格式:
for(数据类型 变量名 : 数组名\集合名){ } -
案例:
/** * Created by PengZhiLin on 2021/8/3 10:16 */ public class Test { public static void main(String[] args) { // 创建Collection集合对象,限制集合元素的类型为String类型 Collection<String> col = new ArrayList<>(); // 往集合中添加元素 col.add("谢霆锋"); col.add("王宝强"); col.add("贾乃亮"); col.add("陈羽凡"); // 增强for循环 for (String name : col) { System.out.println("name:" + name); //col.add("潘粤明");// 报并发修改异常 //col.remove(name);// 报并发修改异常 } System.out.println("--------------------"); // 创建String类型的数组,并存储元素 String[] arr = {"陈冠希", "罗志祥", "吴签", "林俊杰"}; // 增强for循环 for (String name : arr) { System.out.println("name:" + name); } } }
第三章 泛型
3.1 泛型的概述
-
概述: JDK5之后,新增了泛型(Generic)语法,可以在类、接口或方法中预支地使用未知的类型
-
简而言之: 泛型其实就是表示一种未知的数据类型,在使用的时候确定其具体数据类型
-
表示方式: <泛型变量> 泛型变量任意字母
-
泛型的好处:
- 将运行时期的ClassCastException,转移到了编译时期变成了编译失败
- 避免了类型转换的麻烦
-
案例:
-
集合不使用泛型
-
可能会发生类型转换异常
-
避免类型转换异常,就需要先做类型判断,再转型--->比较麻烦
/** * Created by PengZhiLin on 2021/8/3 10:44 */ public class Test { public static void main(String[] args) { // 创建Collection集合,不使用泛型 Collection col = new ArrayList(); // 往集合中添加元素 col.add("张三"); col.add(18); col.add("中国北京"); col.add(3.14); System.out.println("col:" + col); // 循环遍历 for (Object obj : col) { // 获取字符串元素的长度,打印输出 //String str = (String)obj; //System.out.println("字符串元素的长度:"+str.length()); // 避免类型转换异常 if (obj instanceof String){ String str = (String)obj; System.out.println("字符串元素的长度:"+str.length()); } } } }
-
-
集合使用泛型
-
概述:指定泛型的具体数据类型----->(只能是引用数据类型)
/** * Created by PengZhiLin on 2021/8/3 10:44 */ public class Test { public static void main(String[] args) { // 创建Collection集合,使用泛型 Collection<String> col = new ArrayList(); // 往集合中添加元素 col.add("张三"); //col.add(18);// 编译报错 col.add("中国北京"); //col.add(3.14);// 编译报错 System.out.println("col:" + col); // 循环遍历 /* for (Object obj : col) { // 获取字符串元素的长度,打印输出 //String str = (String)obj; //System.out.println("字符串元素的长度:"+str.length()); // 避免类型转换异常 if (obj instanceof String){ String str = (String)obj; System.out.println("字符串元素的长度:"+str.length()); } }*/ for (String str : col) { System.out.println("字符串元素的长度:"+str.length()); } } }
-
-
3.2 定义和使用含有泛型的类
-
定义含有泛型的类
-
格式:
public class 类名<泛型变量>{ } 泛型变量: 可以是任意字母,eg: A,B,E,...a,b,....;一般写E -
案例
/** * Created by PengZhiLin on 2021/8/3 10:54 */ public class MyGenericClass<E> { // 成员变量 E e;// 未知类型的成员变量 // 成员方法 public E method(E e){ return e; } }
-
-
使用含有泛型的类
-
创建含有泛型的类的对象的时候,指定泛型的具体数据类型(只能是引用数据类型)
-
案例
/** * Created by PengZhiLin on 2021/8/3 11:02 */ public class Test { public static void main(String[] args) { // 创建含有泛型的类的对象的时候,指定泛型的具体数据类型(只能是引用数据类型) // 创建MyGenericClass对象,指定泛型的具体数据类型为String MyGenericClass<String> mc1 = new MyGenericClass<>(); // 访问MyGenericClass类的成员变量 mc1.e = "itheima"; System.out.println("e:" + mc1.e); // 访问MyGenericClass类的成员方法 String res1 = mc1.method("itcast"); System.out.println("res1:"+res1); System.out.println("---------------"); // 创建MyGenericClass对象,指定泛型的具体数据类型为Integer MyGenericClass<Integer> mc2 = new MyGenericClass<>(); // 访问MyGenericClass类的成员变量 mc2.e = 100; System.out.println("e:" + mc2.e); // 访问MyGenericClass类的成员方法 Integer res2 = mc2.method(200); System.out.println("res2:"+res2); } }
-
3.3 定义和使用含有泛型的接口
-
定义含有泛型的接口
-
格式:
public interface 接口名<泛型变量>{ } // 泛型变量:可以是任意字母,一般写E -
案例:
/** * Created by PengZhiLin on 2021/8/3 11:08 */ public interface MyGenericInterface<E>{ E method1(E e); }
-
-
使用含有泛型的接口
-
方式一: 实现类实现接口的时候,确定接口泛型的具体数据类型
-
格式:
public class 类名 implements 接口名<具体的引用数据类型>{} -
案例:
/** * Created by PengZhiLin on 2021/8/3 11:11 */ public class MyImp1 implements MyGenericInterface<String> { @Override public String method1(String s) { return "String字符串"; } }
-
-
方式二:实现类实现接口的时候,不确定接口泛型的具体数据类型,而是创建实现类对象的时候确定泛型的具体数据类型
-
格式:
public class 类名<泛型变量> implements 接口名<泛型变量>{} -
案例:
/** * Created by PengZhiLin on 2021/8/3 11:13 */ // 实现类实现接口的时候不指定接口泛型的具体数据类型 public class MyImp2<E> implements MyGenericInterface<E>{ @Override public E method1(E e) { return e; } }public class Test { public static void main(String[] args) { // 创建MyImp1对象 MyImp1 imp1 = new MyImp1(); String res1 = imp1.method1("itheima"); System.out.println("res1:"+res1); // 创建MyImp2对象,指定泛型的具体数据类型为String MyImp2<String> imp2 = new MyImp2<>(); String res2 = imp2.method1("itcast"); System.out.println("res2:"+res2); // 创建MyImp2对象,指定泛型的具体数据类型为Integer MyImp2<Integer> imp3 = new MyImp2<>(); Integer res3 = imp3.method1(100); System.out.println("res3:"+res3); } } -
-
3.4 定义和使用含有泛型的方法
-
定义含有泛型的方法
-
格式:
修饰符 <泛型变量> 返回值类型 方法名(形参列名){ 方法体 } // 泛型变量:可以写任意字母,一般写T -
案例:
/** * Created by PengZhiLin on 2021/8/3 11:22 */ public class MyGenericMethod { public <T> T method(T t){ return t; } }
-
-
使用含有泛型的方法
-
调用含有泛型方法的时候,确定泛型的具体数据类型
-
案例:
/** * Created by PengZhiLin on 2021/8/3 11:23 */ public class Test { public static void main(String[] args) { // 调用含有泛型方法的时候,确定泛型的具体数据类型 Integer res1 = MyGenericMethod.method(100); System.out.println("res1:"+res1); String res2 = MyGenericMethod.method("itheima"); System.out.println("res2:"+res2); } }
-
3.5 泛型通配符
-
概述: 泛型通配符用问号表示(?)
-
为什么需要泛型通配符:
-
泛型本身不存在继承关系,不可以给已指定泛型的变量接收有其他泛型类型的对象
- 翻译: 左边变量泛型指定什么类型,右边对象的泛型就是什么类型,如果不一致就会报错(无论是否有父子关系,都报错)
- eg: Collection
col = new ArrayList ();// 正确的 - eg: Collection
col = new ArrayList ();// 错误的 - ...
-
如果想要使变量在未来接收有泛型定义的对象,又不确定泛型要定义的类型可以使用泛型通配符
- Collection<?> col3 = new ArrayList
();// 正确的 - Collection<?> col4 = new ArrayList
();//正确的 - Collection<?> col5 = new ArrayList
- Collection<?> col3 = new ArrayList
-
浙公网安备 33010602011771号