JAVA小白的崛起之路(九)容器
定义 :容器就是一个可以存储多个数据而且是多种类型的类,而且存储的数据个数是可以任意改变的。
数组与容器的区别:
- 数组可以存储基本数据类型,也可以存储引用数据类型,集合只能存储引用数据类型。
- 数组是固定长度的,集合的长度是可变的。
- 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
ArrayList
与LinkedList
的区别和有缺点:
容器的概念:
在Java当中,如果有一个类专门用来存放其它类的对象,这个类就叫做容器,或者就叫做集
合,集合就是将若干性质相同或相近的类对象组合在一起而形成的一个整体。
容器比数组有的优点:
1.数组难以扩充,容器可以自动扩充。
2.数组中的数据类型必须一样,而容器里却可以多样化。
3.容器不是数组,不能通过下标的方式访问里面的元素,但是数组的所有功能都可以通过ArryList
容器来实现。
4.如果非要把容器里面的元素当做数组来用,也可以用toArray方法返回为一个数组。
2、 从底层实现阐述一下ArrayList
和LinkedList
在不同场景下的效率
ArrayList
底层实现:
ArrayList
是通过数组实现,当我们实例化空Arraylist
的时候就调用一个无参构造函数,初始长
度为10,其他用法跟数组的使用方法相同,但是元素超过10的时候就会自动调用
Array.copyOf(objArr, objArr.length + 1)
方法来让数组扩容。
LinkedList
底层实现:
底层的数据结构是基于双向循环列表的,且头结点和尾结点是不存放数据的,每一个数据可包含在
一个节点里面,节点包括前节点信息和数据和后节点信息三个部分。
不同场景下的使用:
1.如果是大量元素进行存取,Arraylist
的效率,要远高于Linkedlist
,因为Arraylist
可以直接用下标
进行存取,而 LinkedList
加入每个元素时需要每一次都遍历到最后一行才加进去。
2.如果在元素里面进行插入或者删除,则 LinkedList
的效率远高于Arraylist
,因为Arraylist
t加入和删
除的时候后面的每个元素下标都需要加1或者减1,而LinkedList
不需要。
底层用双向链表实现的List。特点:查询效率低,增删效率高,线程不安全。 底层 用数组实现的List。特点:查询效率高,增删效率低,线程不安全。
接口层面图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lBiGCoJk-1604988354416)(JAVA小白的崛起之路(九)容器.assets/1.png)]
Collection接口
Collection是一个接口,只是规定了一些方法,即作为一个容器就应该具有这些功 能。在Collection中并没有任何的可以存储数据的地方,因此只是作为一个规范存 在。
List遍历的三种方式:
普通for循环 ,利用List元素有下标的特点,依次获取每一个元素
for (int i=0; i<list.size(); i++){
System.out.println(list.get(i));
}
增强for 依次获取集合中每一个元素存入一个临时变量中
for (String temp : list) {
System.out.println(temp);
}
迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
迭代器:对象用来指向容器中的一个元素,指向一个元素之前的位置
1、先通过容器获取一个和当前容器相关的迭代器(游标), 默认位置在第一个元素之前
2、利用迭代器提供的方法, hasNext
方法,判断是否有下一个元素
3、如果有,就获取下一个元素,同时让游标向后走一个,next()
map
Map也是容器的一种,但是没有继承Collection接口,以键值对的形式存放数据, 一个key对应一个value 。key和value都是引用数据类型,我们可以通过key找到对 应的value
Map类中存储的键-值对通过 键 来标识,所以 键值不能重复 。
HashMap中存储数据的特点:
- 存储的元素是以K-V的形式存在的 map集合中 key 必须要唯一,
- 如果添加了相同的键值对(键相同)会发生覆盖
- map集合中元素(键值对)是无序的,和Set集合类似
Map遍历的三种方法
keySet
将所有的 key 获取存入 Set 集合中,遍历存储 key 的 Set 集合,结合 get(key) 方法可以获取map 中每一个 key 以及对应的 value。
Set<Integer> keys = num.keySet();
System.out.println("---------增强for------");
for(Integer key : keys){
System.out.println(key + "-" + num.get(key));
System.out.println("-------迭代器-------");
Set<Integer> keys = num.keySet();
Iterator<Integer> keyIt = keys.iterator();
while(keyIt.hasNext()){
// 获取下一个key
Integer key = keyIt.next();
String value = num.get(key);
System.out.println(key + "-" + value);
}
EntrySet
将Map集合中的每一个键值对作为一个 Entry 对象获取到一个Set集合中,通过对 象的 getKey 和 getValue 方法获取 key 和 value
System.out.println("===========Entry的遍历==========");
Set<Entry<Integer, String>> entrySet = num.entrySet();
for(Entry<Integer, String> entry : entrySet){
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "-" + value);
}
System.out.println("-------迭代器-----------");
Set<Entry<Integer, String>> entrySet = num.entrySet();
Iterator<Entry<Integer,String>> it = entrySet.iterator();
while(it.hasNext()){
Entry<Integer, String> en = it.next();
System.out.println(en.getKey() + "-" + en.getValue());
values
将所有的 value 值获取后存入Collection集合中,遍历存储了所有 key 的集合,则可 以获取到所有的 value 值,但此种方式只能获取到每一个value,并不能获取到key。
Collection<String> values = num.values();
for(String v :values){
System.out.println(v);
}
TreeSet
1、不能有重复的元素;
2、具有排序功能;
3、TreeSet中的元素必须实现Comparable接口并重写compareTo()方法,
TreeSet判断元素是否重复 、以及确定元素的顺序 靠的都是这个方法;
①对于Java类库中定义的类,TreeSet可以直接对其进行存储,如String,Integer等,因为这些类已经实现了Comparable接口);
②对于自定义类,如果不做适当的处理,TreeSet中只能存储一个该类型的对象实例,否则无法判断是否重复。
4、依赖TreeMap。
5、相对HashSet,TreeSet的优势是有序,劣势是相对读取慢。根据不同的场景选择不同的集合。
为什么返回0,只会存一个元素,返回-1会倒序存储,返回1会怎么存就怎么取呢?
原因在于TreeSet底层其实是一个二叉树机构,
且每插入一个新元素(第一个除外)都会调用compareTo()方法去和上一个插入的元素作比较,并按二叉树的结构进行排列。
如果将compareTo()返回值写死为0,元素值每次比较,都认为是相同的元素,这时就不再向TreeSet中插入除第一个外的新元素。
所以TreeSet中就只存在插入的第一个元素。
如果将compareTo()返回值写死为1,元素值每次比较,都认为新插入的元素比上一个元素大,于是二叉树存储时,会存在根的右侧,读取时就是正序排列的。
如果将compareTo()返回值写死为-1,元素值每次比较,都认为新插入的元素比上一个元素小,于是二叉树存储时,会存在根的左侧,读取时就是倒序序排列的。
会抛出一个 异常:java.lang.ClassCastException
显然是出现了类型转换异常。
原因在于我们需要告诉TreeSet如何来进行比较元素,如果不指定,就会抛出这个异常
如何解决:
如果将compareTo()返回值写死为-1,元素值每次比较,都认为新插入的元素比上一个元素小,于是二叉树存储时,会存在根的左侧,读取时就是倒序序排列的。
会抛出一个 异常:java.lang.ClassCastException
显然是出现了类型转换异常。
原因在于我们需要告诉TreeSet如何来进行比较元素,如果不指定,就会抛出这个异常
如何解决:
如何指定比较的规则,需要在自定义类(Person)中实现Comparable接口,并重写接口中的compareTo方法