摘要:
今天对集合和集合的一些方法做了整理,以及迭代器的使用,一直以来泛型的使用对我来说都是难点,今天终于突破了,最后对数据结构做了一些简单的介绍,但对于java来说,数据结构显得不那么重要(了解原理即可)。
1.Collection
1.1集合概述
-
集合的作用:
- 集合是一个容器,可以存储同种类型的多个数据。
-
集合的特点:
-
集合的长度是可变的,可以随时给集合增加长度或减少长度。
-
集合只能存储引用数据类型,不能存储基本数据类型
存字符串:ArrayList<String> 存整数: ArrayList<Integer> 如果要存基本类型必须写出对应的包装类
-
1.2Collection常用方法
方法 | 说明 |
---|---|
boolean add(E e) | 添加方法 |
void clear() | 清空集合中的元素 |
boolean remove(Object e) | 删除集合中的某个元素 |
boolean contains(Object obj) | 判断集合是否包含某个元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 获取集合的长度 |
Object[] toArray() | 把集合转成Object[]类型 |
-
示例代码:
public class Demo常用方法 { public static void main(String[] args) { //创建对象 Collection<String> coll = new ArrayList<>(); //boolean add(E e) E代表的就是<>里面的类型 //添加方法 coll.add("柳岩"); coll.add("美美"); System.out.println(coll); //void clear() //清空集合中的元素 //coll.clear(); //boolean remove(Object e) //删除集合中的某个元素,如果有多个重复,只会删除第一个 coll.remove("美美"); //返回的结果是删除成功或失败,但是这个返回值没有使用价值,所以我们一般不需要接受返回值 //boolean b2 = coll.remove("甜甜"); //System.out.println(b2); System.out.println(coll); //boolean contains(Object obj) //判断集合是否包含某个元素 boolean b = coll.contains("柳岩"); System.out.println(b); //true //boolean isEmpty() //判断集合是否为空,如果集合是空的就会返回true boolean b2 = coll.isEmpty(); System.out.println(b2); //false //int size() //获取集合的长度 int size = coll.size(); System.out.println(size); //1 //Object[] toArray() //把集合转成Object[]类型 Object[] arr = coll.toArray(); //System.out.println(arr); //数组打印会出现地址值 System.out.println(Arrays.toString(arr)); } }
2.Iterator迭代器
2.1迭代器的作用
迭代器是帮助Collection集合遍历元素的。
2.2迭代器如何获取
Collection集合有这个方法:
方法 | 说明 |
---|---|
Iterator iterator() | 获取迭代器对象 |
2.3迭代器常用方法
- Iterator接口常用的有两个方法:
方法 | 说明 |
---|---|
E next() | 获取集合中的元素 |
boolean hasNext() | 判断集合中有没有下一个元素 |
void remove() | 删除当前元素 |
-
示例代码:
public class Demo迭代器 { public static void main(String[] args) { //创建对象 Collection<String> coll = new ArrayList<>(); coll.add("柳岩"); coll.add("柳岩"); coll.add("美美"); coll.add("花花"); coll.add("蘑菇"); //遍历集合 //获取迭代器对象 Iterator<String> it = coll.iterator(); //使用循环获取每一个元素 /* 如果有下一个元素,循环里面就是true,就会继续循环获取 如果没有下一个元素,循环里面就是false,循环就会自动结束 */ //快捷键:itit while(it.hasNext()){ String s = it.next(); System.out.println(s); } } }
2.4迭代器原理
-
源码
public boolean hasNext() { //cursor代表指针,默认值是0 //size代表长度,也就是集合的长度 return cursor != size; } @SuppressWarnings("unchecked") public E next() { checkForComodification(); //记录指针位置 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); //让指针向下移动一次 cursor = i + 1; //获取集合中i位置的元素 return (E) elementData[lastRet = i]; }
2.5迭代器的问题:并发修改异常
-
异常:
在迭代器使用的时候,可以会出现一个错误,这个错误叫做并发修改异常
ConcurrentModificationException
-
产生原因:
在迭代器遍历集合的时候,如果使用集合对象对集合的长度进行操作(增加或删除元素),就会出现并发修改异常。
-
代码演示:
public class Demo并发修改异常 { public static void main(String[] args) { //创建对象 Collection<String> coll = new ArrayList<>(); coll.add("柳岩"); coll.add("柳岩"); coll.add("美美"); coll.add("花花"); coll.add("蘑菇"); //遍历集合 //获取迭代器对象 Iterator<String> it = coll.iterator(); //使用循环获取每一个元素 while(it.hasNext()){ //给集合添加一个元素 coll.remove("柳岩"); //这里会报错!!!! String s = it.next(); System.out.println(s); } } }
-
解决办法:
-
添加时出现并发修改异常,现在无法解决。
-
删除时出现并发修改异常。
public class Demo并发修改异常 { public static void main(String[] args) { //创建对象 Collection<String> coll = new ArrayList<>(); coll.add("柳岩"); coll.add("柳岩"); coll.add("美美"); coll.add("花花"); coll.add("蘑菇"); //遍历集合 //获取迭代器对象 Iterator<String> it = coll.iterator(); //使用循环获取每一个元素 while(it.hasNext()){ String s = it.next(); if(s.equals("柳岩")){ //使用迭代器对象删除当前元素 it.remove(); } } System.out.println("打印集合" + coll); } }
-
2.6增强for循环
-
作用:
增强for循环也是可以遍历Collection集合和数组
-
格式:
for(元素的类型 元素名 : 集合/数组){ } 快捷键:iter
-
代码演示
public class Demo增强for循环 { public static void main(String[] args) { //创建对象 Collection<String> coll = new ArrayList<>(); coll.add("柳岩"); coll.add("柳岩"); coll.add("美美"); coll.add("花花"); coll.add("蘑菇"); //增强for循环 for(String s : coll){ System.out.println(s); } } }
-
增强for的特点:
- 好处在于:
- 特别简单
- 缺点在于:
- 增强for的底层也是迭代器也会出现并发修改异常
- 不能使用索引
- 好处在于:
3.泛型
3.1泛型的作用
-
不使用泛型
存的时候可以存任何类型,但是取出来不方便使用
-
使用泛型
规定了要存储的类型,取出来也方便使用
-
代码演示
public class Demo泛型的使用 { public static void main(String[] args) { //创建对象 Collection coll = new ArrayList(); //添加元素 coll.add("abc"); coll.add(123); coll.add(3.14); //遍历 for (Object o : coll) { System.out.println(o); } //使用泛型 Collection<String> coll2 = new ArrayList<>(); //添加元素 coll2.add("abc"); coll2.add("defg"); //coll2.add(123); //遍历 for (String s : coll2) { System.out.println(s); } //使用泛型就规定了集合的存储类型,方便取出元素并使用 } }
3.2泛型的定义
在集合中我们是在【使用】泛型,而不是【定义】泛型。
泛型不仅可以在集合中使用,也可以在别的地方使用。
接下来学习自己定义泛型并使用泛型。
1.类上定义泛型
-
类上定义泛型格式:
//泛型代表的是某一种引用数据类型 public class MyArrayList<T> { }
-
何时确定类型:
- 在每次创建对象时确定具体的类型。
-
代码演示:
//T代表是任意一种引用类型 public class MyArrayList<T> { public void add(T t){ } } public class Demo类上定义泛型 { public static void main(String[] args) { //创建对象 MyArrayList<String> list = new MyArrayList<>(); //泛型确定为了字符串类型 list.add("123"); //list.add(123); //创建对象 MyArrayList<Integer> list2 = new MyArrayList<>(); //泛型确定为了整数类型 list2.add(123); //list2.add("abc"); } }
2方法上定义泛型
-
方法上定义泛型格式:
public <T> void method(T t){ }
-
何时确定类型:
- 在每次调用方法时确定具体类型
-
代码演示:
public class AAA { //方法上定义泛型 public <T> void method(T t){ } } public class Demo方法上定义泛型 { public static void main(String[] args) { //创建对象 AAA a = new AAA(); //调用方法泛型确定为字符串 a.method("abc"); //调用方法泛型确定为整数 a.method(123); } }
3接口上定义泛型
-
接口上定义泛型格式:
//泛型代表某种引用数据类型 //泛型的定义是在<>写一个大写字母 public interface MyColl<T> { void method(T t); }
-
何时确认类型:
- 在定义子类时确定泛型具体的类型
- 在子类上不确定具体类型,就把接口的泛型变成类上的泛型
-
代码演示:
-
在定义子类时确定泛型具体的类型
public class MyAAA implements MyColl<String>{ //在子类中确定了泛型的具体类型 @Override public void method(String s) { } }
-
在子类上不确定具体类型,就把接口的泛型变成类上的泛型
public class MyBBB<T> implements MyColl<T> { //重写父类抽象方法 @Override public void method(T t) { } } //接口的泛型变成类的泛型,就遵守类泛型的规则,在创建类的对象时确定具体的类型 public class Demo接口的泛型 { public static void main(String[] args) { //创建MyBBB对象 MyBBB<String> mb = new MyBBB<>(); mb.method("123"); } }
-
3.3泛型通配符
-
格式:
<?> :可以传递任何的泛型类型 <? extends XXX> :可以传递XXX以及XXX的子类类型 <? super XXX> :可以传递XXX以及XXX的父类类型
-
示例代码:
import java.util.ArrayList; public class Demo泛型通配符 { public static void main(String[] args) { //要求调用下面这个方法 ArrayList<String> list = new ArrayList<>(); ArrayList<Integer> list2 = new ArrayList<>(); ArrayList<Object> list3 = new ArrayList<>(); //method<? extends Object> //method(list); //method(list2); //method(list3); //method<? super String> method(list); //method(list2); 报错! method(list3); } //定义方法 //如果在<?>表示各种泛型类型都能传递, <?>叫做通配符 //public static void method(ArrayList<?> list){ //} //<? extends XXX> :可以传递XXX以及XXX的子类类型 //public static void method(ArrayList<? extends Object> list){ //} //<? super XXX> :可以传递XXX以及XXX的父类类型 public static void method(ArrayList<? super String> list){ } }
3.4泛型在开发中的使用
我们绝大多数的时候只是使用泛型,而不是定义泛型。
学完泛型之后也和之前一样,只要在使用集合时和以前一样会用就可以了。
常用:使用泛型3.1 和使用泛型通配符3.3。
对于3.2的定义泛型我们是不需要定义的,学习它是为了大家看源码的时候能看懂。
4.数据结构
4.1栈和队列
栈:
栈是一个线性表结构,只有一个出入口,从同一个口存放数据和移出数据。
特点:先入后出
队列:
队列也是一个线性表,队列有两个开口,从一边存入数据,从另一边取出数据
特点:先入先出
4.2数组和链表
数组:
数组是在内存中开辟的一块连续的内存空间。
特点:增删慢,查询快
链表:
链表在内存中是不连续的内存空间,数据结构有单向链表和双向链表。现在我们介绍单向链表,单向链表的意思就是前一个结点记录后一个结点的位置。
特点:增删快, 查询慢
4.3树
-
树的介绍
在生活中树就是有树根,有树枝有树叶。
-
二叉树
如果树中的每个节点的子节点的个数不超过2,那么该树就是一个二叉树。
-
二叉查找树(*)
-
左子树上所有的节点的值均小于他的父节点的值
-
右子树上所有的节点值均大于他的父节点的值
-
每一个子节点最多有两个子树
二叉查找树的排序:
按照【左中右】的方式就能够获取到从小到大排列的元素:
10 15 17 20 34 40
-
-
平衡二叉树
- 什么叫平衡
- 如何保持平衡
-
红黑树
总结(跟之前一样,需要及的部分做了记号)
Collection
介绍:
单列集合的根接口
常用方法【记】
size():获取集合的长度
add():添加元素
remove():删除某一个元素
isEmpty():判断集合是否为空
contains():判断集合是否包含某个元素
clear() :清空集合
toArray():把集合转成Object[]类型
iterator():使用集合获取迭代器对象
两种遍历方式
迭代器Iterator【理解并记住】
hasNext():判断有没有下一个元素
next():获取下一个元素
remove():删除当前元素
增强for【理解并记住】
并发修改异常【理解】
产生原因:
在迭代器遍历的同时,使用集合对元素进行增删,就会出现并发修改异常。
解决办法:
不要在遍历的同时增加元素。
如果要删除元素可以使用迭代器对象调用remove()。
泛型
要会在集中中使用泛型【理解】
定义泛型【了解】
在类上定义泛型
在方法上定义泛型
在接口上定义泛型
泛型通配符
<?> :可以接受任何类型【不常见】
<? extends XXX> :可以接受XXX和XXX的子类类型,泛型的上限。【常见】
<? super XXX> :可以接受XXX和XXX的父类类型,泛型的下限。【常见】
数据结构【理解并记】
栈
先进后出
队列
先进先出
数组
增删慢,查询快
链表
增删快,查询慢
二叉查找树
可以对元素进行大小排序