- 常见的数据结构
数组的特点是初始化的时候就指定了长度,是通过索引值连续来组装数据的,我们利用了数组编写了自定义容器,实现对象的增删改查操作。
链表结构是利用对象的引用地址指向下一个对象将所有的对象链接起来,这种方式创建的容器是将对象在内存空间中是零散随机存在。
- 删除:也是链表比较快,只需要断开所要删除的元素,把后一个元素挂在删除的前一个元素上面, 而数组的删除,需要后面的数组全部往前移动;(删除链表结构快,模拟数组容器类比较慢)
- 查找: 链表的查找是依次往后进行查找,而数组是通过索引直接就拿到值,所以数组比较快;
总结:添加和删除链表结构快于数组结构,查询数组结构要快于链表结构。
1.1. 队列
队列是一种线性结构的数据结构,先进先出原则。
堆栈
堆栈 (先进后出原则FILO),例如洗盘子。
- List集合也叫列表,最大的特点是容器内装的内容(对象或元素)是有序的,也称为序列
- List中的元素允许重复(两个对象equals为true)
ArrayList是List接口的实现类,继承了AbstractList,
public class ArrayList<E> extends AbstractList<E> implements List<E>
内部基于数组实现的一个集合类,查询比较快,添加和删除相对比较慢,它的结构和功能和List的另外一个实现类Vector差不多,他们俩最大的区别就是ArrayList不是线程同步的,Vector是线程同步的。
面试题:ArrayList和Vector的关系和区别?
面试题:ArrayList和LinkedList的关系和区别?
1.原理不一样 ArrayList基于数组,查找修改快 添加删除慢 LinkedList基于链表实现,添加删除快
查询 修改慢
2.两者都是集合框架中的容器,可以存储重复的数据,都是List接口的实现类
3.LinkedList可以用来模拟队列以及堆栈的数据结构
4.LinkedList相对于ArrayList多了很多的方法,其实操作链表的头部和尾部的一些方法
1.1. Queue和Deque
结构:Queue和Deque都是接口,Deque接口继承Queue接口,LinkedList是Deque的实现类。
- Queue表示一种队列,也是一种数据结构,它的特点是先进先出,因此在队列这个接口里面提供了一些操作队列的方法,同时LinkedList也具有这些方法;
- Deque(Double ended queues双端队列),支持在两端插入或者移除元素; 那也应该具有操作双端队列的一些方法;
- LinkedList是他们的子类,说明都具有他们两者的方法;LinkedList也可以充当队列,双端队列,堆栈多个角色;
1.1. 判断重复的标准
其实HashSet判断是否相同的标准是要满足两个条件:
- 判断hashcode是否相等
- 判断equals是否相等
当两个条件同时满足的情况下那么在HashSet中的这两个对象就是相等的。
- Comparable 和Comparator的区别:
① Comparable 是一个比较的标准,里面有比较的方法,对象要具有比较的标准,就必须实现Comparable接口;类实现这个接口,就有比较的方法; 把元素放到TreeSet里面去,就会自动的调用CompareTo方法; 但是这个Comparable并不是专为TreeSet设计的;只是说TreeSet顺便利用而已; 就像haashCode和equals 也一样,不是说专门为HashSet设计一样;只是你顺便利用而已;
② Compartor是个比较器,也不是专门为TreeSet设计。就是一个第三方的比较器接口;如果对象没有比较性,自己就可以按照比较器的标准,设计一个比较器. 创建一个类,实现这个接口,覆写方法; 比如可以把Compartor 看成一个裁判,什么足球裁判,篮球裁判都是按照这样的标准进行设计,但是他们里面具体的比较方法是不同的;
将键映射到值的对象
什么是map
Map接口
|---HashMap 判断重复的标准和HashSet一致,通过键的hashcode和equals;
|---TreeMap 判断重复的标准和TreeSet一致,通过对键的判断重复
1通过自然排序(Comparable接口),compareTo方法返回0表示重复
2定制排序(Compartor比较器),compare方法返回0表示重复
这就是HashMap,TreeMap的特点;
面试题:HashMap和HashTable之间的关系区别?
1.HashMap是线程不安全 效率高一些
2.HashTable是线程安全的 同步
HashMap允许他的键为null HashTable的键不允许null
1、HashMap是继承自AbstractMap类,而HashTable是继承自Dictionary类。不过它们都实现了同时实现了map、Cloneable(可复制)、Serializable(可序列化)这三个接口。
2、Hashtable比HashMap多提供了elments() 和contains() 两个方法。
3、HashMap的key-value支持key-value,null-null,key-null,null-value四种。而Hashtable只支持key-value一种(即
key和value都不为null这种形式)。既然HashMap支持带有null的形式,那么在HashMap中不能由get()方法来判断
HashMap中是否存在某个键, 而应该用containsKey()方法来判断,因为使用get的时候,当返回null时,你无法判断到底
是不存在这个key,还是这个key就是null,还是key存在但value是null。
4、线程安全性不同,HashMap的方法都没有使用synchronized关键字修饰,都是非线程安全的,而Hashtable的方法几乎
都是被synchronized关键字修饰的。但是,当我们需要HashMap是线程安全的时,怎么办呢?我们可以通过Collections.synchronizedMap(hashMap)来进行处理,亦或者我们使用线程安全的ConcurrentHashMap。ConcurrentHashMap虽然也是线程安全的,但是它的效率比Hashtable要高好多倍。因为ConcurrentHashMap使用了分段锁,并不对整个数据进行锁定。
5、初始容量大小和每次扩充容量大小的不同
Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。
6、计算hash值的方法不同
为了得到元素的位置,首先需要根据元素的 KEY计算出一个hash值,然后再用这个hash值来计算得到最终的位置。
Hashtable直接使用对象的hashCode。hashCode是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值。然后再使用除留余数发来获得最终的位置。
这里写图片描述
Hashtable在计算元素的位置时需要进行一次除法运算,而除法运算是比较耗时的。
HashMap为了提高计算效率,将哈希表的大小固定为了2的幂,这样在取模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
HashMap的效率虽然提高了,但是hash冲突却也增加了。因为它得出的hash值的低位相同的概率比较高,而计算位运算
为了解决这个问题,HashMap重新根据hashcode计算hash值后,又对hash值做了一些运算来打散数据。使得取得的位置更加分散,从而减少了hash冲突。当然了,为了高效,HashMap只做了一些简单的位处理。从而不至于把使用2 的幂次方带来的效率提升给抵消掉。
---------------------
最近在看Vector与ArrayList的源码,看下他们的区别与联系。
- Vector是线程安全的集合类,ArrayList并不是线程安全的类。Vector类对集合的元素操作时都加了synchronized,保证线程安全。
- Vector与ArrayList本质上都是一个Object[] 数组,ArrayList提供了size属性,Vector提供了elementCount属性,他们的作用是记录集合内有效元素的个数。与我们平常调用的arrayList.size()和vector.size()一样返回的集合内有效元素的个数。
- Vector与ArrayList的扩容并不一样,Vector默认扩容是增长一倍的容量,Arraylist是增长50%的容量。
- Vector与ArrayList的remove,add(index,obj)方法都会导致内部数组进行数据拷贝的操作,这样在大数据量时,可能会影响效率。
- Vector与ArrayList的add(obj)方法,如果新增的有效元素个数超过数组本身的长度,都会导致数组进行扩容。
1.1. Properties重要方法
- Object setProperty(String key, String value)
- String getProperty(String key)
- String getProperty(String key, String defaultValue) ;
如果通过key没有找到对应的键值对,返回后面的defaultValue
// 下面才是最重要的
- void list(PrintStream out)
简单理解: 此方法可以把Properties中的数据写入磁盘文件
- void load(InputStream inStream)
简单理解: 可以把磁盘文件中的数据读取到Properties中来
写数据:①准备把Properties的数据保存到磁盘文件
Properties中方法: void list(PrintStream out)
调用方法,创建一个PrintStream类型的对象 printStream(String filename)
public static void write() throws FileNotFoundException{
Properties pro = new Properties();
pro.put("zhangsan", "123456");
pro.put("lisi", "123456");
pro.put("wangwu", "123456");
pro.put("zhaoliu", "123456");
System.out.println(pro);
System.out.println(pro.getProperty("lisi"));
System.out.println(pro.getProperty("zhaoqi","00000"));
pro.list(new PrintStream("pwd.txt"));
}
读数据:② 把磁盘文件的内容读到Properties中,比如读取eclipse插件路径
public static void read() throws IOException {
Properties pro = new Properties();
InputStream inStream = new FileInputStream("E:\workspace\11_Map\pwd.txt");
pro.load(inStream);
System.out.println(pro);
练习遍历 map的两种方式;(keyset和entrySet);