Collection
- 一、什么是集合框架
- 只能保存对象
- 1.数组和集合都是对多个数据进行存储,java容器
- 二、数组和集合框架的区别?
- 1.数组只能存储相同类型的数据 int[] arr=new int[10];arr只能保存整数
- 集合可以存储不同类型的数据,但我们一般不会让他保存不同类型的数据,一般会加上泛型进行限制
- 2.数组可以保存基本数据类型的数据,也可以保存引用数据类型的数据,
- 集合框架只能保存对象(集合框架里面的数据都是对象)
- 3.数组的弊端:Student[] stu=new Student[10]:这个数组只能保存10个学生信息
- 数组的长度一旦定义,是不可改变的
- 集合可以存储数量不确定的数据
- 三、集合框架的分支
- Collection接口:单列集合,存储一个个对象的
-
--List接口:存储有序的,可以重复的数据 --动态数组
-
--ArrayList、LinkedList、Vector
-
--Set接口:存储无序的,不可重复的
-
--HashSet、LinkedHashSet、TreeSet
- Map接口:多列集合,用来存储一对(key-value)一对的数据
-
--HashMap、LinkedHashMap、TreeMap、Hashtable、Properties
*Java 集合可分为 Set、List 和 Map 三种体系
Set:无序、不可重复的集合,set又是以map为底层实现
List:有序,可重复的集合,list接口是以数组为底层实现,是有序的
Map:具有映射关系的集合,key-value(键值对),map接口底层是hash函数,无续(不是随机)
List
- 一、List接口是collection接口的一个子接口,有序的、可以重复的集合
- 最常用 --ArrayList:主要实现类,底层就是数组 Object[] elementData,,线程不安全,查询速度比较快
-
--LinkedList:底层是使用双向链条的形式进行存储的,添加、删除速度高
-
--Vector:是list接口的古老实现类,线程安全的,效率比较低,Object[] elementData,底层也是数组,jdk1.0
*CTRL+shift+n查找底层源码,查找一个类
-
面试题:ArrayList、LinkedList、Vector
-
相同点:
-
1.都是list集合的实现类
-
2.存储数据的特点相同:有序的、可重复的
-
不同点看上面
-
ctrl+F12是查找方法
-
面试题:list和set集合区别?
- ArrayList底层实现
- List list=new ArrayList();//并且对数组 Object[] elementData进行了初始化,初始化为{}空
- list.add(1);//第一次调用add方法,底层对数组长度进行了指定,指定为10
- 如果添加的新元素导致数组elementData容量不够,进行了扩容,扩容了1.5倍,
- 同时将原数组的元素值复制到了扩容后的新数组里面
- LinkedList
- List list=new LinkedList():在内部声明了Node类型的first和last属性值,默认为null
- list.add(1); //调用add方法,把1封装到node中,创建了Node对象
- node的定义为:node:保存数据的
- Node(Node prev, E element, Node next) {
this.item = element;
this.next = next;
this.prev = prev;
}
Vector:在调用无参构造方法Vector()的时候,底层创建了一个长度为10的数组
它扩容的是2倍
list独有的方法:
// void add(int index, Object ele):根据坐标index把元素添加到指定的位置
// boolean addAll(int index, Collection eles):根据坐标index把集合中所有的元素值添加到指定的位置
// Object get(int index):根据索引值查询对应的元素
// int indexOf(Object obj):查询元素obj第一次出现的索引值,如果找不到返回-1
// int lastIndexOf(Object obj)
// Object remove(int index):根据索引值删除该元素
// Object set(int index, Object ele):根据索引值修改元素
增删改 查 size()方法
Map
- map保存时具有映射关系的数据,保存的就是两组值(一组是key,一组是value)
- 1.Map和collection是一个平行关系
- 2。存放的数据都是键值对(key-value)
- 二、map的结构
- Map中的key:无序、不可重复、使用set存储的,学号,唯一不可重复
- Map中value:无序、可重复的,使用collection进行存储的,姓名,可重复
- key和value的组合就是一个Entry对象
- Entry:无序的、不可重复的,使用set进行存储的
- 三、map的实现类
- HashMap:map的主要实现类,线程不安全,效率高,存储null的key和value
-
-- LinkedHashMap:HashMap的子类,保证在变量map元素的时候,按照添加的顺序进行输出元素值
-
原因:在HashMap这个类的基础上,添加了一对指针,指向上一个元素的引用地址和下一个元素的引用地址,
-
遍历效率比HashMap高
- TreeMap:可以保证key-value进行排序,有序的输出,(自然排序和自定义排序)
- Hashtable:古老的实现,线程安全的,效率低,不能存储null的key和value
-
--Properties:用来处理配置文件,jdbc
-
四、map的常用方法(增删改查)
-
Object remove(Object key):根据key删除元素Object put(Object key,Object value):添加元素,键值对
void putAll(Map t):把集合t添加到当前集合中
void clear();清除
Object get(Object key):根据key查询对应的元素值
boolean containsKey(Object key):判断当前集合中是否包含指定的key
boolean containsValue(Object value):判断当前集合中是否包含指定的value
int size():获取元素的个数
boolean isEmpty():判断是否为空
boolean equals(Object obj):比较
//和遍历相关的三个方法
元视图操作的方法:
Set keySet():返回所有的key构成set集合
Collection values():返回所有的value构成collection集合
Set entrySet():返回所有的key-value的组合entry,构成一个set集合
底层为数组长度为16,16*0.75=12,会在12处进行扩容
*四、HashMap的底层实现?面试重点 多家公司都有这个面试题
- Map map=new HashMap();对加载因子进行了初始化,//初始化成0.75f,就是扩容的一个界限
- map.put(123,123):首次调用put方法的时候,创建了一个长度为16的Node[]数组,
- 并且对临界值进行了初始化为12,//临界值,12处进行扩容
- 添加一个元素put(key1,value1),调用key1所在类的hashcode方法,计算key1的哈希值,对哈希值
- 通过一些算法进行计算,得key1元素的位置,拿着这个位置去Node[]数组里面去找位置,
- 如果此位置数据为空,key1,value1添加成功。
- 如果此位置上的元素不为空,如果key1的哈希值和已经存在的一个数据(key2-value)哈希值不相同,
- 直接添加成功。
- 如果key1的哈希值和已经存在的一个数据(key2-value)哈希值相同
- 调用key1的equals方法和key2进行比较:
- 如果equals比较的结果返回false,此key1,value1添加成功(已链条的形式存在)
*如果equals比较的结果返回true,使用value1替换value2的值 - jdk1.8hashMap底层结构:数组+链条+红黑树也叫二叉树,当链条长度大于8,或者数组长度大于64的时候,这个时候链条就会变成红黑树
- 当数组的某一个索引的位置上的元素以链条的形式纯在的数据个数>8 并且数组的长度>64的时候,此位置变成了红黑树
- 进行存储数据
- 面试:HashMap和Hashtable
//Properties 类是 Hashtable 的子类,该对象用于处理属性文件
//由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型
//存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法
//Properties:处理配置文件,key和value都是String类型
Set
- 一、Set接口继承collection接口
- Set接口的特点:无序的、不可重复的
-
--HashSet:主要实现类,底层是数组,线程不安全的,初始化长度是16,根据保存的位置进行输出
-
--LinkedHashSet:是HashSet的子类,遍历内部数据的时候,可以按照添加的顺序进行遍历,根据添加的顺序进行输出
-
就遍历数据的话,LinkedHashSet效率要高于HashSet,因为可以按照添加的顺序进行遍历,
-
-- TreeSet:可以按照添加对象的指定属性,进行排序。自然排序、自定义排序规则
- 注意:set没有自己定义的方法,用的都是collection接口里面的公共方法
- 二、什么是无序性
- 无序性不等于随机性,是根据哈希值来决定数据的位置
- 存储的数据在底层并非按照数组的索引进行添加的,而是根据每个元素的哈希值决定的
- 不可重复性:保证添加的元素按照equals方法进行判断是,不能返回true,相同的元素只能添加一个
- 必须重写equals方法和hasCode方法
- 1.我们向HashSet里面添加元素a的时候,首先调用元素a所在类的hasCode方法,计算元素a的哈希值,
- 计算出哈希值以后通过一些算法计算在HashSet底层在数组中存放的位置,判断数组的此位置有没有元素,
- 如果没有,直接把元素a添加到该位置(重写后hascode相同元素的哈希是一样的)
- 2.如果此位置有其他元素b,则比较两个元素的值是否相等(equals),
- 如果相等,元素a添加不成功
- 如果不相等,通过链条的方式把元素a添加的元素B的后面
Collections
- Collections和collection的区别?
- Collections 是一个操作 Set、List 和 Map 等集合的工具类
- collection是set和list的一个父接口
- 排序操作:(均为static方法),静态方法的属于类,可以直接通过类名直接去调用这个方法
reverse(List):反转 List 中元素的顺序,只针对于List集合的
shuffle(List):对 List 集合元素进行随机排序
sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
Object min(Collection)
Object min(Collection,Comparator)
int frequency(Collection,Object):返回指定集合中指定元素的出现次数,返回的类型是int类型
void copy(List dest,List src):将src中的内容复制到dest中
boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
泛型
//泛型接口 dao对数据库表进行crud操作:就是增删改查操作
//一个项目得有n个模块,每个模块是不是都得有crud操作
//数据库中的表映射到java里面对应的是一个实体类,要求实体类的属性名,必须和表的列明相同
//对user进行crud操作
//泛型类
//实现数组的复制:泛型方法所以在的类可以不是泛型类
//把数组里面的元素复制到list集合里面
//方法的返回值类型,返回的是一个list集合
//String[]
//int[]
//实现是String类型的数组赋值
//public List<String> //这是返回值类型 copyArrayToList(//这是方法的参数 String[] e//这是数组,List<String> list//这是集合)
//public List<E> copyArrayToList(E[] e,List<E> list)//E会发红色,显示报错,因为他默认会把E当成一个类,而E我们没有定义
//那怎么让他成为一个泛型呢?
public <E>//必须加上这个<E> List<E> copyArrayToList(E[] e,List<E> list)
//实现Double类型数组复制
public List copyArrayToList(Double[] e,List list){//他默认会把E当成一个类
//复制
for(Double e2:e){
list.add(e2);
}
return list;
}
//泛型方法:
public List copyArrayToList(E[] e,List list){//他默认会把E当成一个类,提高了方法的复用性,减少方法重载
//复制
for(E e2:e){
list.add(e2);
}
return list;
}
}
- <>里面不能写int,因为集合里面都是对象,没有基本数据类型这个概念,所以要保存整数的话,应该用Integer这个包装类
- 泛型的使用:
- 1.Jdk5.0出现的一个新特性
- 2.可以有效避免强制类型转换引发的异常
- 3.限制集合的数据类型,提高了数据类型的安全性
- 4.讲运行时异常转成了编译时异常
- 二、在集合中使用泛型
- 1.集合接口和集合实现类在jdk5.0的时候都改成了泛型结构
- 2.在实例化集合的时候,我可以指定具体的泛型类型
- 3.如果在实例化集合的时候,没有指定泛型类型,默认类型就是Object类型
- 4.指明完成以后,在集合接口或集合类里面,内部结构(属性、方法)使用此类泛型的位置,
- 都指定为了实例化的泛型类型:
- List list=new … boolean add(E e);变成了boolean add(Integer e);
- 注意:泛型的类型必须是类,也就是引用数据类型,不能是基本数据类型,如果要使用基本数据类型的话,
- 使用基本数据类型对应的包装类,因为集合里面保存的都是对象
- 常用的几个字母
- ?: 表示不确定java类型
- T(type):表示一个java类型
- K(key):map中的键 key
- V(value):map中的值value
- E(element):代表一个element
- 泛型的声明
interface List 和 class Test<K,V>
其中,T,K,V不代表值,而是表示类型。这里使
用任意字母都可以。常用T表示,是Type的缩写
泛型的实例化:
一定要在类名后面指定类型参数的值(类型)。如:
List strList = new ArrayList();
Iterator iterator = customers.iterator();
T只能是类,不能用基本数据类型填充。
- 三、什么时候使用泛型?
- 1.当操作引用类型不确定的时候可以使用泛型
- 2.<>里面就是一个用于接收具体类型的代表
- 四、泛型类
- 1.定义泛型类:在类名后面通过<>指定一个或多个类型参数,如果多个的话
- 需要通过,隔开 class Person<K,V>
- 2.如果自定的泛型类在实例化对象的时候没有指定泛型类型,默认就是object
- 3.如果在实例化对象的时候指定了泛型类型,指定后对应类后面使用的泛型位置就是已确定为实例化中指定的类型
- 五、泛型方法
- 1.在定义泛型方法的时候,需要在方法的访问修饰符后面通过<>指定泛型方法的类型
- 2.泛型方法的定义和所在类是不是泛型没有任何关系
- 六、泛型接口(三层架构):dao层:数据库访问层(操作数据库,对数据库数据进行增删改查):数据库持久层,表示层
- 七、通配符的使用
//子类继承父类,如果在继承的时候指定了泛型的类型,在创建对象的时候可以不用指定泛型
//子类继承父类,如果在继承的时候没有指定了泛型的类型,在创建对象的时候就必须指定泛型
//注意:泛型方法和泛型类之间没有任何关系,就是在泛型方法里面我可以单独定义一个泛型,泛型方法所在的类可以不是泛型类
//使用泛型方法的好处?
//提高了方法的复用性,减少方法重载
- 泛型在继承方面:了解
- 虽然A是B的父类,但是E和E两者没有父子关系
- 我们可以找一个通用的父类
- 通配符?
- 不知道用什么类型来接受的时候,可以用?标识