第一章 集合
1.1 集合概述
- 定义:集合是java提供的一种容器,用来存储多个数据。
- 数组与集合的区别:
- 数组的长度是固定的,集合长度是可变的
- 数组中存储的是基本数据类型或者对象,集合存储的都是对象
1.2 集合框架
1.2.1 单列集合(Collection)
- 定义:单列集合类的根接口。
- 子接口:
- List子接口:
- 特点:元素有序可重复
- 实现类:
- ArrayList
- LinkedList
- Vector
- Set子接口:
- 特点:元素无序不可重复
- 实现类:
- TreeSet
- HashSet
- LinkedHashSet(元素有序)
- List子接口:
1.2.2 双列集合(Map)
- 实现类:
- HashMap类
- LinkedHashMap子类
- Hashtable类
- HashMap类
1.3 Collection集合
1.3.1 Collection接口
-
定义:由于它是一个接口,我们无法直接使用,需要间接使用Collection接口的实现类对象来操作集合。
-
Collection对象创建:Collection接口有很多的实现类,例如ArrayList类。 (多态)
-
常用方法:
public boolean add(E e): 把给定的对象添加到当前集合中 public void clear(): 清空集合中所有的元素 public boolean remove(E e): 把给定的对象在当前集合中删除 public boolean contains(E e): 判断当前集合中是否包含给定的对象 public boolean isEmpty(): 判断当前集合是否为空 public int size(): 返回集合中元素的个数 public Object[] toArray(): 把集合中的元素,存储到数组中
1.3.2 Iterator接口
-
定义:也叫迭代器,用于集合的遍历,由于它是一个接口,我们无法直接使用,需要间接使用Iterator接口的实现类对象来操作集合。
-
Iterator对象创建:Collection接口中有一个方法叫做iterator(),返回的就是迭代器的实现类对象**(多态)**
-
迭代器使用步骤:
- 使用Collection中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收
- 获取实现类对象,并会把指针指向集合的-1索引
- 使用Iterator接口中的方法hasNext判断还有没有下一个元素
- 使用Iterator接口中的方法next取出集合中的下一个元素
- 第一步:取出下一个元素
- 第二步:指针后移一位
例如:
// 遍历集合中的元素 Iterator<String> iter = coll.iterator(); while(iter.hasNext()){ System.out.println(iter.next()); }
- 使用Collection中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收
-
常用方法:
boolean hasNext(): 判断集合中还有没有下一个元素 E next(): 取出集合中的下一个元素
-
增强for:
-
定义:内部原理也是Iterator迭代器,专门用来遍历集合和数组
-
格式:
for(元素的数据类型 变量 : 集合or数组){ }
遍历共有三种方式:通过索引(有索引),通过Iterator,通过增强for
-
1.3.3 List子接口
-
三大特点:
- 它是一个元素存取有序的集合
- 它是一个带索引的集合
- 它可以包含重复的元素
-
常用方法:
public void add(int index, E e): 添加元素 public E get(int index): 获取元素 public E remove(int index): 删除元素 public E set(int index, E e): 设置元素(不可新增元素,只能修改元素)
1.3.3 ArrayList类
-
特点:底层是数组结构,因此增删慢,查找快
-
创建对象:
- 格式:ArrayList 对象名 = new ArrayList<>();
- 注意:
- 代表泛型,也就是装在集合当中的所有元素,全都是统一的什么类型
- 泛型只能是引用类型,不能是基本类型
- 对于ArrayList集合来说,直接打印得到的不是地址值,而是内容,如果内容是空,得到的是空的中括号:[]
-
常用方法:
public boolean add(E e): 向集合当中添加元素,参数的类型和泛型一致 public E get(int index): 从集合当中获取元素,参数是索引编号,返回值就是对应位置的元素 public E remove(int index): 从集合当中删除元素,参数是索引编号,返回值就是被删除的元素 public int size(): 获取集合的尺寸长度,返回值就是集合中包含的元素个数
1.3.4 LinkedList类
-
特点:底层是链表结构,因此增删快,查找慢
-
常用方法:
public void addFirst(E e): 将指定元素插入到此列表的开头 public void addLase(E e): 将指定元素插入到此列表的结尾 public E getFirst(): 返回此列表的第一个元素 public E getLast(): 返回此列表的最后一个元素 public E removeFirst(): 移除并返回此列表的第一个元素 public E removeLast(): 移除并返回此列表的最后一个元素 public E pop(): 弹出一个元素 【等效于 removeFirst(E e)】 public void push(E e): 推入一个元素 【等效于 addFirst(E e)】 public boolean isEmpty(): 如果列表不包含元素,返回true
1.3.5 Vector类(了解)
底层和ArrayList一样,也是数组结构
1.3.6 Set子接口
- 特点:
- 不允许存储重复的元素
- 没有索引,因此没有带索引的方法
- 常用方法:和Collection接口一致
1.3.7 HashSet类
-
特点:
- 它是一个元素存取无序集合
- 底层是一个哈希表结构,查询速度非常的快
-
常用方法:和Collection接口一致
-
哈希表:
jdk1.8版本之前:哈希表=数组+链表
jdk1.8版本之后:哈希表=数组+链表/红黑树
注意:数组结构:把元素进行了分组(相同哈希值的元素是一组);链表/红黑树结构:把相同哈希值的元素链接到一起。如果链接到一起的数据超过了8个,会把链表转换为红黑树结构。
-
调用add方法的过程:
集合在调用add方法的时候,会同时调用hashCode方法和equals方法,判断元素是否重复(如果两个元素的哈希值相同,就会调用equals方法,进而判断两个元素是否相同,相同就不会存储该元素)
总结:HashSet存储元素的时候,必须重写hashCode方法和equals方法。(Alt+Insert)
1.3.7.1 LinkedHashSet类
- 特点:底层是一个哈希表+链表:多了一条链表(用来记录元素的存储顺序),保证元素有序
1.3.8 可变参数
-
使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用
-
使用格式:定义方法时使用
修饰符 返回值类型 方法名(数据类型…变量名){}
-
原理:底层是一个数组,根据传递参数的个数不同,会创建不同长度的数组,来存储这些参数,传递的参数个数可以是0个、1个…
-
注意事项:
- 一个方法的参数列表,只能有一个可变参数
- 如果方法的参数有多个,那么可变参数写在参数列表的末尾
-
终极写法:
修饰符 返回值类型 方法名(Object… obj){}
1.4 Collections工具类
-
常用静态方法:
public static <T> boolean addAll(Collection<T> list, T... elements): 往集合中添加一些元素 public static void shuffle(List<?> list): 打乱集合顺序 public static <T> void sort(List<T> list): 将集合中元素按照默认规则排序 public static <T> void sort(List<T> list, Comparator<? super T>): 将集合中元素按照指定规则排序
注意:
-
sort(List list)使用前提:被排序的集合里边存储的元素,必须实现Comparable接口,要重写接口中的compareTo方法(定义排序规则)
-
Comparable接口的排序规则:【自己(this) 减 参数 表示升序】
-
Comparator和Comparable的区别:
- Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口
- Comparator:相当于找一个第三方的裁判,比较两个
// 按照指定规则排序----使用匿名对象和匿名内部类 Collections.sort(list, new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { // return o1-o2; // 升序 return o2-o1; // 降序 } });
-
1.5 Map集合
1.5.1 Map接口
-
特点:
- 它是一个双列集合,一个元素包含两个值(一个key,一个value)
- 集合中的元素,key和value的数据类型可以相同,也可以不同
- 集合中的元素,key是不允许重复的,value是可以重复的
- 集合中的元素,key和value是一一对应的
-
常用方法:
public V put(K key, V value): 把指定的键与指定的值添加到Map集合中(key不重复返回null,key重复会使用新的value替换旧的value,返回被替换的value) public V remove(Object key): 把指定的键所对应的的键值对元素在Map集合中删除(key存在返回被删除的value,key不存在返回null) public V get(Object key): 根据指定的键,在Map集合中获取对应的值 boolean containsKey(Object key): 判断集合中是否包含指定的键 public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中 public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合
-
Entry键值对对象:
- 定义:在Map接口中有一个内部接口Entry
- 作用:当Map集合一创建,那么就会在Map集合中创建一个Entry对象,用来记录键与值的映射关系。
- 常用方法:【getKey() :获取key】 【getValue():获取value】
-
遍历:
- 利用keySet方法遍历的步骤:
- 获取集合中所有的key值,并存入Set集合中
- 遍历Set集合即可
- 利用entrySet方法遍历的步骤:
- 获取集合中所有的Entry对象,并存入Set集合中
- 遍历Set集合即可
- 利用keySet方法遍历的步骤:
注意:作为key的元素,必须重写hashCode方法和equals方法,以保证key不重复
1.5.2 HashMap实现类
- 特点:
- 底层是哈希表,查询速度特别快
- 它是一个无序集合
- 注意:
- HashMap存储自定义类型键值的时候,如果要保证key不重复,在自定义类中必须重写hashCode方法和equals方法。(快捷键生成)
- 它会自动按照key值进行排序(与哈希值有关)
1.5.2.1 LinkedHashMap子类
- 定义:extends HashMap
- 特点:
- 底层是哈希表+链表
- 它是一个有序集合
1.5.3 Hashtable实现类
-
特点:
- 底层也是一个哈希表,是一个线程安全的集合,是单线程的集合,速度慢
- 不可以存储null值、null键
- 它和Vector集合一样,在jdk1.2版本之后被更先进的集合(HashMap,ArrayList)取代了
- 它的子类Properties依然活跃在历史舞台
-
Properties集合
java.util.Properties
:extends Hashtable<k,v> implements Map<k,v>- 作用:Properties集合是一个唯一和IO流相结合的集合
- 可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入硬盘中存储
void store(OutputStream out, String comments)
:不可以写入中文,comments注释void store(Writer writer, String comments)
:可以写入中文
- 可以使用Properties集合中的方法load,把硬盘中保存的文件(键值对),读取到集合中使用
void load(InputStream input)
void load(Reader reader)
- 可以使用Properties集合中的方法store,把集合中的临时数据,持久化写入硬盘中存储
- 属性列表中每个键及其对应值都是一个字符串(默认)
- 操作字符串的特有方法.:
Object setProperty(String key, String value)
:相当于Map集合中的put(key,value)String getProperty(String key)
:相当于Map集合中的get(key)Set<String> stringPropertyName()
:相当于Map集合中的keySet()(用于集合的遍历)
1.5.4 补充知识点
- JDK9的新特性:
- 概述:List接口、Set接口、Map接口:里边增加了一个静态的方法of,可以给集合一次性添加多个元素
- 格式:static List of (E… elements)
- 使用前提:当集合中存储的元素的个数已经确定了,不在改变时使用
- 注意:
- of方法只适用于List接口、Set接口、Map接口,不适用于接口的实现类
- of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法来添加元素
- Set接口和Map接口在调用of方法的时候,不能有重复的元素
第二章 泛型
2.1 泛型概述
泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型。例如E、T
2.2 使用泛型的好处
- 创建集合对象,不使用泛型
- 好处:默认的类型是Object类型,可以存储任意类型的数据
- 弊端:不安全,易引发异常
- 创建集合对象,使用泛型
- 好处:避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型;把运行期异常提升到了编译期
- 弊端:泛型是什么类型,就只能存储什么类型的数据
2.3 泛型的定义和使用
-
定义和使用含有泛型的类:
// 定义 public class GenericClass<E> { private E name; public E getName() { return name; } public void setName(E name) { this.name = name; } } // 使用 public class Demo05Generic { public static void main(String[] args) { GenericClass<Integer> gc = new GenericClass<>(); gc.setName(123); System.out.println(gc.getName()); } }
注意:创建集合对象的时候,就会确定泛型的数据类型
- 定义和使用含有泛型的方法:
// 格式:修饰符 <泛型> 返回值类型 方法名(参数列表){} // 定义 public class GenericMethod { public <M> void method01(M m){ System.out.println(m); } } // 使用 public class Demo06Generic { public static void main(String[] args) { GenericMethod gm = new GenericMethod(); gm.method01("sunlei"); gm.method01(10); } }
注意:在调用方法的时候确定泛型的数据类型。
-
定义和使用含有泛型的接口:
- 实现类的定义方式:
- 第一种实现方式:定义接口的实现类,实现接口,指定接口的泛型
- 第二种实现方式:接口使用什么泛型,实现类就使用什么泛型,类跟着接口走
// 接口定义 public interface GenericInterface<T> { public abstract void method(T i); } // 实现类定义的两种方式 // 第一种方式 public class GenericInterfaceImpl implements GenericInterface<String>{ @Override public void method(String i) { System.out.println(i); } } public static void main(String[] args) { GenericInterfaceImpl gii = new GenericInterfaceImpl(); gii.method("sunlei"); } // 第二种方式 public class GenericInterfaceImpl<T> implements GenericInterface<T>{ @Override public void method(T i) { System.out.println(i); } } public static void main(String[] args) { GenericInterfaceImpl<String> gii = new GenericInterfaceImpl<>(); gii.method("sunlei"); }
-
泛型通配符
-
定义:不知道使用什么类型来接收的时候,此时可以使用?表示未知通配符
-
使用方式:不能创建对象使用,只能作为方法的参数使用
ArrayList<?> list = new ArrayList<>(); // 不正确 public static void printArray(ArrayList<?> list){} // 正确
-
高级使用之受限泛型(看懂代码即可)
-
泛型的上限限定:? extends E 代表使用的泛型只能是E类型的子类/本身
-
泛型的下限限定:? super E 代表使用的泛型只能是E类型的父类/本身
// 此时的泛型,必须是Number类型或者Number类型的子类 public static void printArray(ArrayList<? extends Number> list){} // 此时的泛型,必须是Number类型或者Number类型的父类 public static void printArray(ArrayList<? super Number> list){}
-