目录
1.数组和集合的区别
集合体系
Collection集合概述
Collection集合特有遍历方式:迭代器Iterator
迭代器中删除的方法
增强for
List集合
List集合的特有方法
数据结构
栈和队列
数组和链表
List集合的实现类
LinkedList集合
泛型
自定义泛型类:【这个类可以创建各种数据类型的对象】
泛型方法
泛型接口
类型通配符
类型通配符【泛型的上限下限】
1.数组和集合的区别
+ 相同点
都是容器,可以存储多个数据
+ 不同点
+ 数组的长度是不可变的,集合的长度是可变的
+ 数组可以存基本数据类型和引用数据类型
集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类
集合体系
List集合:有存储顺序,允许重复元素,有索引
Set集合:不允许重复,没有索引【不能使用普通for】
Collection集合概述
- 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
- JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现
- 创建Collection集合的对象
- 多态的方式
- 具体的实现类ArrayList
- Collection集合常用方法
方法名 | 说明 |
boolean add(E e) | 添加元素 |
boolean remove(Object o) | 从集合中移除指定的元素 |
boolean removeIf(Object o) | 根据条件进行移除 |
boolean remove(E e) | 把给定的对象在当前集合中删除 |
void clear() | 清空集合中的元素 |
boolean contains(Object o) | 判断集合中是否存在指定的元素 |
boolean isEmpty() | 判断集合是否为空 |
int size() | 集合的长度,也就是集合中元素的个数 |
public Object[] toArray() | 把集合中的元素,存储到数组中。 |
public class Demo01Collection {
public static void main(String[] args) {
//创建集合对象,可以使用多态
//Collection<String> coll = new ArrayList<>();
Collection<String> coll = new HashSet<>();//无序的,不允许存储重复元素
System.out.println(coll);//重写了toString方法 []
System.out.println(new ArrayList<String>());//【】
/*
public boolean add(E e): 把给定的对象添加到当前集合中 。
返回值是一个boolean值,一般都返回true,所以可以不用接收
*/
boolean b1 = coll.add("张三");
System.out.println("b1:"+b1);//b1:true
System.out.println(coll);//[张三]
coll.add("李四");
coll.add("李四");
coll.add("赵六");
coll.add("田七");
System.out.println(coll);//[张三, 李四, 赵六, 田七]
/*
public boolean remove(E e): 把给定的对象在当前集合中删除。
返回值是一个boolean值,集合中存在元素,删除元素,返回true
集合中不存在元素,删除失败,返回false
*/
boolean b2 = coll.remove("赵六");
System.out.println("b2:"+b2);//b2:true
boolean b3 = coll.remove("赵四");
System.out.println("b3:"+b3);//b3:false
System.out.println(coll);//[张三, 李四, 田七]
/*
public boolean contains(E e): 判断当前集合中是否包含给定的对象。
包含返回true
不包含返回false
*/
boolean b4 = coll.contains("李四");
System.out.println("b4:"+b4);//b4:true
boolean b5 = coll.contains("赵四");
System.out.println("b5:"+b5);//b5:false
//public boolean isEmpty(): 判断当前集合是否为空。 集合为空返回true,集合不为空返回false
boolean b6 = coll.isEmpty();
System.out.println("b6:"+b6);//b6:false
//public int size(): 返回集合中元素的个数。
int size = coll.size();
System.out.println("size:"+size);//size:3
//public Object[] toArray(): 把集合中的元素,存储到数组中。
Object[] arr = coll.toArray();
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
for (Object o : arr) {
System.out.println(o);
}
//public void clear() :清空集合中所有的元素。但是不删除集合,集合还存在
coll.clear();
System.out.println(coll);//[]
System.out.println(coll.isEmpty());//true
}
}
Collection集合特有遍历方式:迭代器Iterator
- 迭代器介绍
- Iterator<E> iterator(): 返回此集合的迭代器对象,该迭代器对象默认指向当前集合得0索引
- Iterator中的常用方法
boolean hasNext(): 判断当前位置是否有元素可以被取出 - E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置
- void remove(): 删除迭代器对象当前指向的元素【此remove是迭代器的remove≠集合的remove】
- 迭代器的泛型要与集合的泛型保持一致
public class Demo01Iterator {
public static void main(String[] args) {
//创建一个集合对象
Collection<String> coll = new ArrayList<>();
//往集合中添加元素
coll.add("姚明");
coll.add("科比");
coll.add("麦迪");
coll.add("詹姆斯");
coll.add("艾弗森");
/*
1.使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
注意:
Iterator<E>接口也是有泛型的,迭代器的泛型跟着集合走,集合是什么泛型,迭代器就是什么泛型
*/
//多态 接口 实现类对象
Iterator<String> it = coll.iterator();
/*
发现使用迭代器取出集合中元素的代码,是一个重复的过程
所以我们可以使用循环优化
不知道集合中有多少元素,使用while循环
循环结束的条件,hasNext方法返回false
*/
while(it.hasNext()){//需要使用多态写法,子类没有hasnext等方法,需要想上找到接口中的方法
//不可以用coll.iterator()
String e = it.next();
System.out.println(e);
}
System.out.println("----------------------");
for(Iterator<String> it2 = coll.iterator();it2.hasNext();){
String e = it2.next();
System.out.println(e);
}
}
}
迭代器中删除的方法
void remove(): 删除迭代器对象当前指向的元素
public class MyCollectonDemo4 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("b");
list.add("c");
list.add("d");
/*
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
if("b".equals(s)){
list.remove(i);
i--; 【原因:arraylist是一个动态集合,比如一个集合有五个元素,0-4个索引,当删除2号索引后,集合长度减为4,原本2号索引的位置被3号索引所替代,指针开始从“3”号索引开始继续往下,直接跳过了此元素的判断,所以需要i值减一位,从而达到判断3号索引】
}
}
*/
//优化
Iterator<String> it = list.iterator();
while(it.hasNext()){
String s = it.next();
if("b".equals(s)){
//指向谁,那么此时就删除谁.
it.remove(); 【迭代器里的remove解决了此问题】
}
}
System.out.println(list);
}
}
增强for
其内部原理是一个迭代器,只有实现Iterable接口的类才可以使用迭代器和增强for。
Collection继承了此接口可以使用,Map没有实现此接口,不能使用
格式
for(集合/数组中元素的数据类型 变量名 : 集合/数组名) {
// 已经将当前遍历到的元素封装到变量中了,直接使用变量即可
}
三种循环的使用场景
如果需要操作索引,使用普通for循环
如果在遍历的过程中需要删除元素,请使用迭代器如果仅仅想遍历,那么使用增强for
List集合
List集合的特点
- 存取有序
- 可以重复
- 有索引【可以通过索引进行一系列操作】
List集合的特有方法
方法名 | 描述 |
void add(int index,E element) | 在此集合中的指定位置插入指定的元素,原来该索引处元素后移 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
数据结构
栈和队列
栈
队列
数组和链表
数据结构之数组
链表
链表中的每个元素叫结点,结点是一个独立的对象
链表是一个增删快的模型(对比数组)
双向链表:先判断元素离哪一头近,离后头近,则从后往前查找,反之。
List集合的实现类
List集合子类的特点
- ArrayList集合
底层是数组结构实现,查询快、增删慢 - LinkedList集合
底层是链表结构实现,查询慢、增删快
LinkedList集合
特有方法,不能多态创建集合
LinkedList<String> list=new LinkedList<>();
方法名 | 说明 |
public void addFirst(E e) | 在该列表开头插入指定的元素 |
public void addLast(E e) | 将指定的元素追加到此列表的末尾 |
public E getFirst() | 返回此列表中的第一个元素 |
public E getLast() | 返回此列表中的最后一个元素 |
public E removeFirst() | 从此列表中删除并返回第一个元素 |
public E removeLast() | 从此列表中删除并返回最后一个元素 |
泛型
/**
* 不写泛型的弊端
*/
public class GenericitySummarize {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.add(123);
Iterator it = list.iterator();
while(it.hasNext()){
【假如不写上泛型】
(1)默认为object类型即object obj=“aaa”;,而obj中没有length方法,程序运行就会报错。只有通过
强转将obj转为string类,才能调用String特有的length方法。
(2)如果没写泛型,假如add添加一个integer类型数据,那么下面语句中会把integer类数据强转为
String类,而两个类型间无法强转,运行时就会报错,类型不匹配
String next = (String) it.next();
int len = next.length();
System.out.println(len);
}
}
}
泛型的好处
- 把运行时期的问题提前到了编译期间【确定了泛型就可以把错误判断提前到编译期,如果泛型不对会标红处理,提前预知错误】
- 避免了强制类型转换【如果没有泛型,那么add添加的数据默认为object类型,如果想使用比如String泛型的特定方法。length,无法使用,需要先把object类型数据强转为String类型,如果又添加add一个int类型数据,在进行强转就会报错】
泛型的定义格式:
- <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如: <E> <T>
- <类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如: <E,T> <K,V>
可以使用的地方:
类后面 → 泛型类
方法申明上 →泛型方法
接口后面 →泛型接口
泛型类的总结
如果一个类的后面有<E>,表示这个类是一个泛型类。
创建泛型类的对象时,必须要给这个泛型确定具体的数据类型。
public class ArrayList<E>【此类后面<E>表泛型】 extends AbstractList<E> 【Arraylist类】
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
XXX }
【创建集合对象时,就在类这里指定了泛型类型】
ArrayList<String> list=new ArrayList<>();
自定义泛型类:【这个类可以创建各种数据类型的对象】
- 定义格式
修饰符 class 类名<类型> { }
泛型是一个未知的数据类型,当我们不确定什么什么数据类型的时候,可以使用泛型泛型可以接收任意的数据类型,可以使用Integer,String,Student... 创建对象的时候确定泛型的数据类型
在主函数中创建对象时,指定自己想要的泛型类
text<String> tx=new text<>("asdf");
text<Integer> tx=new text<>(123);
示例:
【泛型类】
public class Generic<T> {
private T t;
public T getT() { Alt+insert自动生成get,set
return t;
}
public void setT(T t) {
this.t = t;
}
}
【测试类】
public class GenericDemo1 {
public static void main(String[] args) {
Generic<String> g1 = new Generic<String>();
g1.setT("杨幂");
System.out.println(g1.getT());
Generic<Integer> g2 = new Generic<Integer>();
g2.setT(30);
System.out.println(g2.getT());
Generic<Boolean> g3 = new Generic<Boolean>();
g3.setT(true);
System.out.println(g3.getT());
}
}
泛型方法 【在调用方法的时候确定泛型的数据类型】
- 定义格式
修饰符 <泛型类型> 返回值类型 方法名(泛型类型 变量名) { } 【修饰符后的<类型>表创建的是一个泛型方法】
含有泛型的方法,在调用方法的时候确定泛型的数据类型传递什么类型的参数,泛型就是什么类型
- 示例代码
【带泛型方法的类】
public class Generic {
public <T> void show(T t) {
System.out.println(t);
}
}
【测试类】
public class GenericDemo2 {
public static void main(String[] args) {
Generic g = new Generic();
g.show("柳岩");
g.show(30);
g.show(true);
g.show(12.34);
}
}
泛型接口
定义格式
修饰符 interface 接口名<泛型类型> { }
eg:
public interface GenericInterface<I> { public abstract void method(I i); //虽然是一个泛型方法,但在接口处就已经声明了这是一个泛型//所以在修饰符处不用在写<I>了 }
泛型接口的使用方式:
实现类也不给泛型【在创建实现类对象的时候指定泛型】
实现类确定具体的数据类型
- 示例代码
【泛型接口】
public interface Generic<T> {
void show(T t);
}
【泛型接口实现类1】
定义实现类时,定义和接口相同泛型,创建实现类对象时明确泛型的具体类型
public class GenericImpl1<T> implements Generic<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
【泛型接口实现类1】
定义实现类时,直接明确泛型的具体类型
public class GenericImpl2 implements Generic<Integer>{
@Override
public void show(Integer t) {
System.out.println(t);
}
}
【测试类】
public class GenericDemo3 {
public static void main(String[] args) {
GenericImpl1<String> g1 = new GenericImpl<String>();
g1.show("林青霞");
GenericImpl1<Integer> g2 = new GenericImpl<Integer>();
g2.show(30);
GenericImpl2 g3 = new GenericImpl2();
g3.show(10);
}
}
类型通配符
类型通配符
- 类型通配符: <?>
- ArrayList<?>: 表示元素类型未知的ArrayList,它的元素可以匹配任何的类型
- 但是并不能把元素添加到ArrayList中了,获取出来的也是父类类型
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(2);
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("b");
printArray(list01);
printArray(list02);
//ArrayList<?> list03 = new ArrayList<?>();
}
/*
定义一个方法,能遍历所有类型的ArrayList集合
这时候我们不知道ArrayList集合使用什么数据类型,可以泛型的通配符?来接收数据类型
注意:
泛型没有继承概念的
*/
public static void printArray(ArrayList<?> list){
//使用迭代器遍历集合
Iterator<?> it = list.iterator();
while(it.hasNext()){
//it.next()方法,取出的元素是Object,可以接收任意的数据类型
Object o = it.next();
System.out.println(o);
}
}
}
- 类型通配符上限: <? extends 类型>
- ArrayListList <? extends Number>: 它表示的类型是Number或者其子类型
- 类型通配符下限: <? super 类型>
- ArrayListList <? super Number>: 它表示的类型是Number或者其父类型
- 泛型通配符的使用
public class GenericDemo4 {
public static void main(String[] args) {
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
ArrayList<Number> list3 = new ArrayList<>();
ArrayList<Object> list4 = new ArrayList<>();
method(list1);
method(list2);
method(list3);
method(list4);
getElement1(list1);
getElement1(list2);//报错
getElement1(list3);
getElement1(list4);//报错
getElement2(list1);//报错
getElement2(list2);//报错
getElement2(list3);
getElement2(list4);
}
// 泛型通配符: 此时的泛型?,可以是任意类型
public static void method(ArrayList<?> list){}
// 泛型的上限: 此时的泛型?,必须是Number类型或者Number类型的子类
public static void getElement1(ArrayList<? extends Number> list){}
// 泛型的下限: 此时的泛型?,必须是Number类型或者Number类型的父类
public static void getElement2(ArrayList<? super Number> list){}
}