基本概述
对象数组:
数组和集合存储引用数据类型,存的都是地址值
集合的由来:
数组长度是固定,当添加的元素超过了数组的长度时需要对数组重新定义,太麻烦,java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加,随着元素的减少而减少
集合和数组的区别:
1、存储类型不同
数组既可以存储基本数据类型,又可以存储引用数据类型, 基本数据类型存储的是值,引用数据类型存储的是地址值
集合只能存储引用数据类型(对象)集合中也可以存储基本 数据类型,但是在存储的时候会自动装箱变成对象
2、长度不同
数组长度是固定的,不能自动增长
集合的长度的是可变的,可以根据元素的增加而增长
什么时候用集合,数组?
元素个数固定用数组,不固定用集合
集合的框架图:
单列集合的顶层接口Collection
List体系
特点:有序(元素存取的顺序是一致的),可重复,有索引
ArrayList:底层的数据结构是数组。
Vector:底层的数据结构是数组。
LinkedList:底层的数据结构是链表。
Set体系
特点:无序,唯一,无索引
HashSet:底层的数据结构是哈希表。
子类LinkedHashSet
TreeSet:底层的数据结构是二叉树。
双列集合的顶层接口Map
HashMap:底层的数据结构是哈希表。
子类LinkedHashMap
TreeMap:底层的数据结构是二叉树。
Hashtable:底层的数据结构是哈希表。
子类Properties
面试题:
字符串,集合,数组分别怎么获取长度?
字符串:length()方法
集合:size()方法
数组:length属性
分类
单列集合接口:Collection
分类:
Collection中的方法:
boolean add(Object obj); 添加
boolean remove(Object obj); 移除
boolean contains(Object obj);是否包含给定的元素
boolean isEmpty();判断集合是否为空
int size();获取集合中元素的个数。
void clear();清空集合(相当于把集合中的元素都删掉)
Collection中带All功能的方法(了解):
boolean addAll(Collection c); 添加一个集合中的元素到另一个集合中
boolean removeAll(Collection c);删除两个集合中的交集
boolean containsAll(Collection c);判断一个集合是否包含另一个集合
boolean retainAll(Collection c); 判断两个集合是否有交集,把交集 赋值给调用者如果调用者不改变,返回值是false,如果改变,结果是true
集合的遍历方式:
1、转数组遍历:
public Object[] toArray(); 把集合对象转成数组对象
2、迭代器(Iterator)
思路(重点掌握):
1、获取迭代器对象。
public Iterator iterator();Collection接口中的方法根据集合对象获取到迭代器对象
2、判断迭代器中是否有元素。
public boolean hasNext(); Iterator接口里边的,判断迭代器中是否有元素
3、有的话,就可以来获取到这个元素。
public Object next(); Iterator接口里边的,获取集合中的元素
迭代器的原理(了解)
迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,所以每一个集合存和取都是不一样,那么就需要在每一个类中定义hasNext()和next()方法,这样做是可以的,但是会让整个集合体系过于臃肿,迭代器是将这样的方法向上抽取出接口,然后在每个类的内部,定义自己迭代方式,这样做的好处有二,第一规定了整个集合体系的遍历方式都是hasNext()和next()方法,第二,代码有底层内部实现,使用者不用管怎么实现的,会用即可
Iterator接口中只有三个方法:
boolean hasNext()
如果仍有元素可以迭代,则返回 true。
next()
返回迭代的下一个元素
void remove()
从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)
List体系
特点:
有序(元素存取的顺序是一致的),可重复,有索引
List体系概述
List集合的特有功能概述:
void add(int index, Object obj); 在指定位置添加指定元素
Object remove(int index);移除集合中指定位置的元素,并将被移除的元素返回
Object get(int index);根据索引,返回对应位置的元素
Object set(int index,Object obj);修改指定位置的元素
List体系的独有遍历方式:
get()和size()方法结合使用
并发修改异常:ConcurrentModificationException
产生原因:
用普通的迭代器遍历集合的时候,同时对集合中 的元素进行了添加
解决方案:
用列表迭代器(ListIterator)来遍历,并且 通过列表迭代器的add()方法来添加元素
ListIterator列表迭代器:
public boolean hasNext(); 判断集合中是否有下一个元素(正向遍历)
public Object next(); 返回下一个元素
public boolean hasPrevious(); 判断集合中是否有上一个元素(逆向遍历)
public Object previous();返回上一个元素
注意事项:
进行逆向遍历之前,必须先对集合进行 正向遍历,否则结果可能不是我们想要的
Vector类(了解):
(用法跟Interator类似)有些企业中的项目,如果是早起研发的,那么 可能使用的集合是Vector,咱们能看懂他们写的是什么意思就行了
数据结构(数组和链表):
数组:查询快,修改快,增删慢。
因为每个元素都有编号(索引),并且编号从0开始的
链表:查询慢,修改慢,增删快。
List三个儿子的特点:
ArrayList:
底层数据结构是数组,查询快,增删慢。线程不安全,效率高。
Vector:
底层数据结构是数组,查询快,增删慢。线程安全,效率低。
LinkedList:
底层数据结构是链表。查询慢,增删快。线程不安全,效率高。
List三个儿子的区别:
1、ArrayList和Vector的区别
ArrayList是线程不安全的,效率高
Vector是线程安全的,效率低
共同点:都是数组实现的
2、ArrayList和LinkedList的区别
ArrayList底层是数组结构的,查询和修改快,增和删比较慢
LinkedList底层是链表结构的,增和删比较快,查询和修改比较慢
共同点:都是线程不安全的效率高
什么时候使用List的哪个儿子
查询多:ArrayList
增删多:LinkedList
都多,或者你不知道你不知道用谁: ArrayList
分类:
ArrayList
底层数据结构是数组,查询快,增删慢,线程不安全,效率高。
案例:
案例1:ArrayList存储字符串如何去除重复元素
A:创建一个新的集合对象。
B:通过老集合获取一个迭代器对象,然后遍历老集合。
C:判断新集合中是否包含当前遍历到的元素,如果包含, 不添加,如果不包含,就把该元素添加到新集合中。
案例2:ArrayList存储自定义对象如何去除重复元素
注意事项:contains()方法判断集合中是否包含某个元素,或者 remove()移除集合中的某个元素,这两个方法的底层都是调用了 equals()方法,所以我们要在基本类(Person类)中重写equals() 方法,也不要忘记还要重写toString方法
Vector
(了解)用法跟Iterator基本类似,底层数据结构是数组, 查询快,增删慢,线程安全,效率低。
LinkedList
底层数据结构是链表,查询慢,增删快,线程不安全,效率高。
LinkedList的特有方法:
void addFirst() 和 addLast()添加
Object removerFirst() 和 removeLast();删除
Object getFirst() 和 getLast();获取
栈和队列的数据结构:
栈:先进后出
队列:先进先出
面试题:用LinkedList来模拟栈的数据结构
泛型
概述:泛指某种类型
好处:
1、提高安全性(把运行期异常转移到编译期)
2、不用强转了,省去强转的麻烦
格式:
<> <>中的数据类型必须是引用数据类型
注意事项:
前后泛型必须一致,或者后边的泛型可以不写(1.7的新特性菱形泛型)
ArrayList<String> list = new ArrayList<String>();
泛型和增强for都是JDK1.5的新特性
泛型的由来:
以前的集合能存的是Object类型的数据,这样什么类型的数据都可以存进集合了, 但是好多时候我们要做类型转换,这样就不安全。而泛型就是来解决这个问题的
泛型类(了解):
格式:在类名后边加泛型即可
泛型方法(了解):
注意:方法的泛型最好和类的泛型一致
分类:
非静态方法:
1、泛型可以与类的泛型一致,这样不用定义自己的泛型 public void show(T t) { }
2、泛型与类的泛型不一致,需要定义自己的泛型 public <V> void method(V v) { }
静态方法:
格式:
public static <B> void function(B b){ }
必须定义自己的泛型,为什么?
因为静态成员是随着类的加载而加载 的,类加载的时候,对象还没有创建
泛型接口(了解):
格式:在接口名后边加泛型即可
实现方式:
1、用普通类来实现 class Demo1 implements Smoke<Student> { }较常用
2、用泛型类来实现 class Test<T> implements Somke<T> { }
泛型高级之通配符(了解):
<?>
任意类型,如果没有明确,那么就是Object以及任意的Java类了
? extends E
固定上边界(向下限定),E及其子类
? super E
固定下边界(向上限定),E及其父类
集合加强
增强for(foreach):
概述:
简化数组和集合的遍历
格式:
for(元素的数据类型 变量名 : 数组或者集合名){ //具体的功能代码 }
遍历集合:
1、普通for: get(),size()方法
2、迭代器。
3、增强for。底层是依赖于迭代器的
问:这三种遍历方式能不能在遍历 集合的同时,删除集合中的元素
1、普通for:
可以。但是注意索引要记得-- (减减)(看需求)
2、迭代器:
可以,但是要调用迭代器的remove()方法,不要调用集合的remove()方法。
注意:
遍历集合的同时,往集合中添加元素,如果使用的是 普通的迭代器,是不可以的,会报并发修改异常。如 果使用的是列表迭代器,是可以的,但是要使用列表 迭代器中的add()方法。
3、增强for:
不可以
静态导入:
格式:
import static 包名...类名.方法名; 可以直接导入到方法的级别
注意事项:
静态导入只能导入静态方法,如果有多个同名的静态 方法,容易不知道使用谁?这个时候要使用,必须加前 缀。由此可见,意义不大,所以一般不用,但是要能看懂
可变参数:
什么时候使用?
定义的方法,不知道形参的个数的时候就可以考虑使用
格式:
修饰符 返回值类型 方法名(数据类型... 变量名){ } int... b
注意事项:
1、可变参数底层其实是一个数组。
2、如果方法有多个参数,并且有可变参数 时候,可变参数必须放参数列表最后
集合和数组之间的相互转换:
集合转数组:
Collection集合中的toArray()方法
注意:
如果数组的长度大于集合的长度,转 换后的数组长度是数组自己的长度
如果数组的长度小于等于集合的长度 ,转换后的数组长度是集合的长度
数组转集合:
Arrays类中的asList()方法,必须用List来接收
注意:
1、数组转成集合后,集合中的元素不能添加 或删除,但是可以使用集合中的其它方法。
2、要转集合的数组必须是引用类型,如果基本类型, 会直接把该基本类型的数组当做集合中的一个元素。
ArrayList集合的嵌套:
我们学科,学科又分为若干班级,整个学科是 一个大集合,若干班级分别为每一个小集合。
关键点:
1、创建一个学科集合。 ArrayList<ArrayList<Person>> list = ArrayList<>();
2、遍历的时候,通过增强for的嵌套遍历,获取到 每一个学员,然后输出学员的信息。
Set体系
概述:
Set接口与Collection接口中的方法基本一致,只是比Collection接口更加严格了
特点:
无序(存取的顺序不一致),唯一(不可重复),无索引
public boolean add(Object obj); 往set集合中添加重复元素的时候,返回值是false
注意:一个类可以有多个对象,但是一个类的字节码文件对象只有一个
遍历:
1、迭代器
2、增强for(只要能用迭代器迭代,就可以使用增强for)
HashSet类:
如何保证元素的唯一性?
依赖于两个方法:hashCode(),equals()
调用add()方法添加元素的原理
A:调用要添加的对象的hashCode() 方法,计算出该对象的哈希值
B:去集合中找是否有元素的哈希值 和要添加的元素的哈希值相同
如果不同:直接把该元素添加到集合中
如果相同:调用equals方法去比较各个属性的值
如果都相同,不添加
如果不相同,就添加
LinkedHashSet类是HashSet的子类
特点:有序(元素的存取顺序一致),唯一
TreeSet类:
特点:用来对元素进行排序的
两种排序方式:
1、自然排序
让基本类(要排序的类)去实现Comparable 接口,并且重写接口中的compareTo()方法
注意:
二叉树取元素的顺序:左,中,右
当compareTo()方法返回0的时候,集合中只有一个元素
当compareTo()方法返回正数的时候,怎么存就怎么取
当compareTo()方法返回负数的时候,怎么存就倒着取
八种包装类都重写了compareTo方法
2、比较器排序
使用的是 TreeSet(Comparator comparator); TreeSet类的带参构造
做法:
1、新建一个类,去实现Comparator接口, 重写接口中的compare(),然后创建一个该类 对象,传入到 TreeSet类的带参构造中。
2、直接使用匿名内部类。 (推荐)
两种排序方式的区别:
TreeSet构造函数什么都不传, 默认按照类中Comparable 的顺序(没有就报错ClassCastException)
TreeSet如果传入Comparator, 就优先按照Comparator
注意:
用TreeSet排序的时候,一定要考虑清楚什么是主要条件,什么是次要条件
遍历总结:
List体系:
a.普通for循环, 使用get()逐个获取
b.调用iterator()方法得到Iterator, 使用hasNext()和next()方法
c.增强for循环, 只要可以使用Iterator的类都可以用
d.Vector集合可以使用Enumeration的hasMoreElements()和nextElement()方法
Set体系:
a.调用iterator()方法得到Iterator, 使用hasNext()和next()方法
b.增强for循环, 只要可以使用Iterator的类都可以用
双列集合接口:Map
Map体系
Map体系概述
将键映射到值的对象
一个映射不能包含重复的键
每个键最多只能映射到一个值
Map接口和Collection接口有什么不同:
Map集合:双列集合,键是唯一的,数据结构只针对键有效
Collection:单列集合,Set体系是具有唯一性的。数据结构针对集合中的元素有效
Map集合中的方法:
添加:
V put(K key, V value)
如果键是第一次添加,返回null
如果键不是第一次添加,就用新值替换之间的旧值,并且返回之前的旧值
删除:
void clear();移除所有的键值对元素
V reomove(Object key); 根据键,移除该键值对,并把值返回
判断:
boolean containsKey(Object key);判断集合中是否包含给定的键
boolean containsValue(Object value);判断集合中是否包含给定的值
boolean isEmpty();判断集合是否为空
获取:
Set< Map.Entry<K,V> > entrySet();返回 键值对对象的集合
V get(K key);根据键获取值
Set<T> keySet();获取双列集合中,所有键的集合
Collection<V> values();获取双列集合中,所有值的集合
长度:
int size();返回的是集合中键值对的个数
Map集合的遍历:
1、根据键找值
1、通过keySet()方法获取到所有的键
2、遍历第一步获取到的键的集合,拿到每一个键
3、获取到键后,调用get()方法,找到其对应的值
2、获取键值对集合,然后从中获取键和值
1、通过entrySet()方法拿到所有的 键值对对象 的集合
2、遍历第一步获取到的键值对对象的集合,拿到每一对键值对对象
3、获取到键值对对象后,调用getKey(),getValue()方法,找到其对应的键和值
Map.Entry原码解析:
1、Entry<K,V>其实是 Map.Entry<K,V>的一个子类
2、Entry<K,V>其实是一个键值对对象,Map是一个接口,Entry是Map接口中的接口。(内部接口)
HashMap和Hashtable的区别(面试题):
Hashtable(注意t是小写的):JDK1.0以后的,线程安全,效率低。不能存null值和null键。
HashMap: JDK1.2以后的,线程不安全的,效率高。可以存null值和null键。
(加一句:)这两个类也有共同点,他们都是双列集合,底层数据结构都是哈希算法
LinkedHashMap类:
它是HashMap的子类,底层数据结构是链表,可以保证元素的存取顺序是一致(有序)
TreeMap类
底层的数据结构是二叉树,从而保证键的唯一性, 用法跟TreeSet基本一致,只不过它是双列集合。
了解:
Hashtable类实现了Map接口,它还有一个子类 Properties,主要用来存储字符串类型的键和值
Collections集合工具类中的方法:
sort(List list);对给定集合进行排序
binarySearch(List list, Oject obj);二分查找
max(Collection coll);求最大值
reverse(List list);反转
shuffle(List list);随机置换。(相当于“洗牌”)
Collections工具类中全是静态方法,这五个方法中,只有max() 的参数是Collection集合,其它都是对List体系进行操作
泛型:
固定下边界(向上限定)
? super E E类或者E的父类
固定上边界(向下限定)
? extends E E类或者E的子类
什么时候使用哪个集合?
是单列:Collection
是否需要排序或元素是否唯一:
否:List体系
增删多:
LinkedList
查询多:
是否安全
是:Vector
否:ArrayList
是:Set体系
是否需要排序:
是:TreeSet
否:HashSet
是双列:Map
是否需要排序
是:TreeMap
否:HashMap
手绘集合框架结构图
最新推荐文章于 2025-06-04 15:30:31 发布