1.Collection集合
1.1数组和集合的区别【理解】
-
相同点
都是容器,可以存储多个数据
-
不同点
-
数组的长度是不可变的,集合的长度是可变的
-
数组可以存基本数据类型和引用数据类型
集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类
-
1.2集合类体系结构【理解】
1.3Collection 集合概述和使用【应用】
-
Collection集合概述
是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现
collection的特点:
1:有序:部分集合实现是有序的,部分集合实现是无序的。这里的有序指的是存储的顺序。
2:可排序:部分集合实现是可排序的,部分集合实现是不可排序的。
3:可重复:部分集合是可重复的,部分集合是不可重复的。
既然每一个集合的特点不一样,那么就取决于所有子类的实现方法不一样,但是我们知道,在集合中所有的集合应该具有集合共有特点:
1:长度可变
2:能够存储任意的引用类型
3:具备很多对象的增删改查的方法
4:集合也能够存储基本数据类的包装类
-
创建Collection集合的对象
-
多态的方式
-
具体的实现类ArrayList
-
-
Collection集合常用方法
方法名 说明 boolean add(E e) 添加元素 boolean remove(Object o) 从集合中移除指定的元素 boolean removeIf(Object o) 根据条件进行移除 void clear() 清空集合中的元素 boolean contains(Object o) 判断集合中是否存在指定的元素 boolean isEmpty() 判断集合是否为空 int size() 集合的长度,也就是集合中元素的个数 retainALL 求交集,返回的结果是是否有交集,有交集返回true,没有交集返回false
1.4Collection集合的遍历【应用】
所有的实现了Collection接口的集合类都有一个iterator()方法,该方法返回一个Iterator接口对象。提供的有集合数据遍历的方式。
-
迭代器介绍
-
迭代器,集合的专用遍历方式
-
Iterator<E> iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到
-
-
Iterator中的常用方法
boolean hasNext(): 判断当前位置是否有元素可以被取出 E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置
-
Collection集合的遍历
public class IteratorDemo1 { public static void main(String[] args) { //创建集合对象 Collection<String> c = new ArrayList<>(); //添加元素 c.add("hello"); c.add("world"); c.add("java"); c.add("javaee"); //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到 Iterator<String> it = c.iterator(); //用while循环改进元素的判断和获取 while (it.hasNext()) { String s = it.next(); System.out.println(s); } } }
-
迭代器中删除的方法
void remove(): 删除迭代器对象当前指向的元素
public class IteratorDemo2 { 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"); Iterator<String> it = list.iterator(); while(it.hasNext()){ String s = it.next(); if("b".equals(s)){ //指向谁,那么此时就删除谁. it.remove(); } } System.out.println(list); } }
1.5增强for循环【应用】
-
介绍
-
它是JDK5之后出现的,其内部原理是一个Iterator迭代器
-
实现Iterable接口的类才可以使用迭代器和增强for
-
简化数组和Collection集合的遍历
-
所有的单列集合和数组才能用增强for进行遍历
-
-
格式
for(集合/数组中元素的数据类型 变量名 : 集合/数组名) {
// 已经将当前遍历到的元素封装到变量中了,直接使用变量即可
}
-
快速生成方式:集合的名字.for
-
代码
public class MyCollectonDemo1 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.add("e"); list.add("f"); //1,数据类型一定是集合或者数组中元素的类型 //2,str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素 //3,list就是要遍历的集合或者数组 for(String str : list){ System.out.println(str); } } }
2.List集合
2.1List集合的概述和特点【记忆】
-
List集合的概述
-
有序集合,这里的有序指的是存取顺序
-
用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
-
与Set集合不同,列表通常允许重复的元素
-
-
List集合的特点
-
存取有序
-
可以存储重复元素和空值
-
有索引
-
2.2List集合的特有方法【应用】
方法名 | 描述 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
int indexof(object o) | 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。 |
int LastIndexof(object o) | 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。 |
List<E> subList(int fromIndex,int toIndex) | 返回列表中指定的fromIndex(含)和toIndex之间的元素。 |
2.3ListIterator接口
ListIterator接口是Iterator接口的子接口,在Iterator正向迭代的基础上扩展了逆向迭代的操作。
3.数据结构
3.1数据结构之栈和队列【记忆】
栈结构(LIFO)
先进后出
Stack特点:1:基于栈结构的集合,先进后出。2:Stack类是Vector的子类,所以该类也是线程安全的,效率低。
压栈:push
获取栈顶元素:peek
弹栈(获取栈顶的元素并弹出):pop
测试栈是否为空:empty
返回对象在栈中的位置,以1为基数:search(object o)
注:如果栈中的元素为空,那么再次尝试弹栈(pop方法),将会抛出EmptyStackException。
队列结构(FIFO)
先进先出
Queue特点:
1、该接口是队列接口的根接口,先进先出。
2、该接口提供队列相关的两种形式的方法,一种抛异常,一种返回一个特殊的值(null或false)
常用方法:
抛出异常 | 返回特殊值 | |
---|---|---|
插入 | add(e) | offer(e) |
移除 | remove | poll() |
只取数据,不弹出 | element | peek() |
3.2Deque(双端队列)
特点:
1、Deque是一个Queue的子接口,是一个双端队列,支持在两端插入和移除元素。
2、deque支持索引值直接存取。
3、Deque头部和尾部添加或移除元素都非常快速。但是在中部安插元素或移除元素比较费时。
4、插入、删除、获取操作支持两种形式:快速失败和返回null或true\false。
5、不推荐插入null元素,null作为特定返回值表示队列为空。
常用方法:
第一个元素(头部) | 最后一个元素(尾部) | |||
---|---|---|---|---|
抛出异常 | 特殊值 | 抛出异常 | 特殊值 | |
插入 | addFirst(e) | offerFirst(e) | addLast(e) | offerLast(e) |
移除 | removeFirst() | pollFirst() | removeLast() | pollLast() |
检查 | getFirst() | peekFirst() | getLast() | peekLast() |
双向队列操作:
插入元素:
-
addFirst():向队头插入元素,如果元素为null,则发生空指针异常。
-
addLast():向队尾插入元素,如果为空,则发生空指针异常。
-
offerFirst():向队头插入元素,如果插入成功返回true,否则返回false。
-
offerLast():向队尾插入元素,如果插入成功返回true,否则返回false。
移除元素:
-
removeFirst():返回并移除队头元素,如果该元素是Null,则发生NoSuchElementException
-
removeLast():返回并移除队尾元素,如果该元素是Null,则发生NoSuchElementException
-
pollFirst():返回并移除队头元素,如果队列无元素,则返回null
-
pollLast():返回并移除队尾元素,如果队列无元素,则返回null
获取元素:
-
getFirst():获取队头元素但不移除,如果队列无元素,则发生NoSuchElementException
-
getLast():获取队尾元素但不移除,如果队列无元素,则发生NoSuchElementException
-
peekFirst():获取队尾元素但不移除,如果队列无元素,则返回null
-
peekLast():获取队尾元素但不移除,如果队列无元素,则返回null
栈操作:
pop():弹出栈中元素,也就是返回并移除队头元素,等价于removeFirst(),如果队列无元素,则发生NoSuchElementException。
push():向栈中压入元素,也就是向队头增加元素,等价于addFirst(),如果元素为null,则发生NoSuchElementException,如果栈空间受到限制,则发生lllegalStateException。
引用场景:
1、满足FIFO场景时。
2、满足LIFO场景时,曾经在解析XML按标签时使用过栈这种数据结构,但是却选择Stack类,如果在进行栈选型时,更推荐使用Deque类,因为Stack是线程同步。
3.3数据结构之数组和链表【记忆】
-
数组结构
查询快、增删慢
-
队列结构
查询慢、增删快
3.4ArrayDeque
概述:Deque接口的大小可变数组的实现。数组双端队列没有容量限制;它们可根据需要增加以支持使用。它们不是线程安全的;在没有外部同步时,它们不支持多个线程的并发访问。禁止null元素。此类很可能在用作堆栈时快于Stack,在用作队列时快于LinkedList。
特点:
-
ArrayDeque是Deque接口的一种具体实现,是依赖于可变数组来实现的。
-
ArrayDeque没有容量限制,可根据需求自动进行扩容
-
ArrayDeque不支持值为null的元素。
-
ArrayDeque可以作为栈来使用,效率要高于Stack
-
ArrayDeque也可以作为队列来使用,效率相较于基于双向链表的LinkedList也要更好一些。
4.List集合的实现类
4.1List集合子类的特点【记忆】
-
ArrayList集合(可调整大小的数组的实现List接口。实现所有可选列表操作,并允许所有元素,包括null。除了实现List接口之外,该类还提供了一些方法来操纵内部使用的存储列表的数组的大小。这个类大致相当于Vector,不同之处在于它是不同步的)
1.底层是数组结构实现,查询快、增删慢。默认初始长度为0。
2.能够存储null值。
3.线程不安全,效率高。
4.底层是数组结构,那么就意味着查询和修改的效率高,而增加和删除的效率就低了。
5.有索引,能够方便的检索。
6.元素可以重复,我们可以自己通过选择排序法去重。
7.不可排序。
注:ArrayList中常用的方法全部来自于父类Collection,List,Object。
-
LinkedList集合
1、底层是双向链表结构实现,元素有序,可重复。
2、查询,修改慢、增删快。顺序访问会非常高效,而随机访问效率会比较低。
3、LinkedList实现了List接口,支持使用索引访问元素。
4、LinkedList实现Deque接口,所以LinkedList也可以当作双端队列使用。
5、LinkedList是线程不安全的,效率高。
双向链表特点:
1、灵活的空间要求,存储空间不要求连续。
2、不支持下标访问,支持顺序遍历。
3、针对增删效率会高一些,只和操作节点的前后节点有关系,无需移动元素。
4.2LinkedList集合的特有功能【应用】
-
特有方法
方法名 说明 public void addFirst(E e) 在该列表开头插入指定的元素 public void addLast(E e) 将指定的元素追加到此列表的末尾 public E getFirst() 返回此列表中的第一个元素 public E getLast() 返回此列表中的最后一个元素 public E removeFirst() 从此列表中删除并返回第一个元素 public E removeLast() 从此列表中删除并返回最后一个元素
4.3Vector接口
常用方法:
增加:1、void addElement(E obj) 添加元素obj到集合中。
2、void insertElementAt(E obj,int index) 在指定索引 index 处插入元素obj
删除:1、void removeElementAt(int index) 移除指定索引 index 处的元素。
2、void removeAllElements() 移除所有元素。
修改:1、void setElementAt(E obj,int index) 修改指定索引 index 的元素为obj。
遍历:1、for循环。
2、使用Enumeration迭代器遍历集合中的元素。
获取:1、firstElement() 获取集合中的第一个元素
2、lastElement() 获取集合中的最后一个元素
3、ElementAt(int index) 获取指定索引index的元素
特点:
1:底层数据结构是数组
2:有索引,能够方便检索
3:增加和删除效率低,查询和修改的效率高
4:线程安全,效率低
5:能够存储null
6:元素可重复
7:不可以排序
5.泛型
5.1泛型概述【理解】(在编译时就确定类型的一种技术)
-
泛型的介绍
泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制
-
泛型的好处
-
把运行时期的问题提前到了编译期间
-
避免了强制类型转换
-
提高了程序的安全性
-
-
泛型的定义格式
-
<类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如: <E> <T>
-
<类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如: <E,T> <K,V>
-
不能写基本数据类型
-
5.2泛型类【应用】
-
定义格式
修饰符 class 类名<类型> { }
-
示例代码
-
泛型类
public class Generic<T> { private T t; public T getT() { 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()); } }
-
5.3泛型方法【应用】
-
定义格式
修饰符 <类型> 返回值类型 方法名(类型 变量名) { }
-
注意:普通方法可以使用方法声明的泛型或者类泛型。静态方法是不能使用在类名处声明的泛型。
-
示例代码
-
带有泛型方法的类
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); } }
-
5.4泛型接口【应用】
-
定义格式
修饰符 interface 接口名<类型> { }
-
示例代码
-
泛型接口
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); } }
-
泛型接口实现类2
定义实现类时,直接明确泛型的具体类型
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); } }
-
5.5类型通配符(限定类型的范围,泛型不具备继承性,但是数据具备继承性)
-
类型通配符: <?>(无界通配符)
-
ArrayList<?>: 表示元素类型未知的ArrayList,它的元素可以匹配任何的类型
-
但是并不能把元素添加到ArrayList中了,获取出来的也是父类类型
-
-
类型通配符上限: <? 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){} }
应用场景:
1、如果我们在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
2、如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以泛型的通配符。