IT阔论

JAVA面试之基础

2018-10-23  本文已影响22人  默云客

▷ java基本类型、所占字节和范围:

1.整型

类型 字节 范围 描述
byte 1字节 -2^7 ~ 2^7-1 8位、有符号的,以二进制补码表示的整数
short 2个字节 -2^15 ~ 2^15 - 1 16 位、有符号的以二进制补码表示的整数
int 4个字节 -2^31 ~ 2^31 - 1 32位、有符号的以二进制补码表示的整数
long 8个字节 -2^63 ~ 2^63 -1 64 位、有符号的以二进制补码表示的整数

2.浮点型

类型 字节 范围 描述
float 4个字节 -2^128 ~ +2^128(-3.40E+38 ~ +3.40E+38) 单精度、32位、符合IEEE 754标准的浮点数
double 8个字节 -2^1024 ~ +2^1024(-1.79E+308 ~ +1.79E+308) 双精度、64 位、符合IEEE 754标准的浮点数

3.逻辑性

类型 字节 范围 描述
boolean 1/8 个字节 true/false 一位的信息,用掩码取字节最后一位来表示

4.字符型

类型 字节 范围 描述
char 2个字节 0 ~ 65,535(\u0000 ~ \uffff) 单一的 16 位 Unicode 字符,一个字符能存储下一个中文汉字

▷ Set、List、Map的区别和联系

一. 结构特点:
  1. List和Set是存储单列数据的集合,Map是存储键值对这样的双列数据的集合;
  2. List中存储的数据是有顺序的,并且值允许重复;Map中存储的数据是无序的,它的键是不允许重复的,但是值是允许重复的;Set中存储的数据是无顺序的,并且不允许重复,但元素在集合中的位置是由元素的hashcode决定,即位置是固定的(Set集合是根据hashcode来进行数据存储的,所以位置是固定的,但是这个位置不是用户可以控制的,所以对于用户来说set中的元素还是无序的)。
二. 实现类:
  1. List接口有三个实现类
    1.1、LinkedList
    基于链表实现,链表内存是散列的,增删快,查找慢;
    1.2、ArrayList
    基于数组实现,非线程安全,效率高,增删慢,查找快;
    1.3、Vector
    基于数组实现,线程安全,效率低,增删慢,查找慢;
  2. Map接口有四个实现类
    2.1、HashMap
    基于 hash 表的 Map 接口实现,非线程安全,高效,支持 null 值和 null 键;
    2.2、HashTable
    线程安全,低效,不支持 null 值和 null 键;
    2.3、LinkedHashMap
    是 HashMap 的一个子类,保存了记录的插入顺序;
    2.4、SortMap接口
    TreeMap,能够把它保存的记录根据键排序,默认是键值的升序排序
  3. Set接口有三个实现类
    3.1、HashSet
    底层是由 Hash Map 实现,不允许集合中有重复的值,使用该方式时需要重写 equals()和 hash Code()方法;
    3.2、LinkedHashSet
    继承于 HashSet,同时又基于 LinkedHashMap 来进行实现,底层使用的是 LinkedHashMap
    3.3、TreeSet
    基于 TreeMap实现。使用元素的[自然顺序]对元素进行排序,或者根据创建 set 时提供的Comparator进行排序
三. 区别:
  1. List 集合中对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,例如通过list.get(i)方法来获取集合中的元素;
  2. Map 中的每一个元素包含一个键和一个值,成对出现,键对象不可以重复,值对象可以重复;
  3. Set 集合中的对象不按照特定的方式排序,并且没有重复对象,但它的实现类能对集合中的对象按照特定的方式排序,例如 Tree Set 类,可以按照默认顺序,也可以通过实现 Java.util.Comparator< Type >接口来自定义排序方式。
四. 补充:HashMapHashTable

HashMap 是线程不安全的,HashMap 是一个接口,是 Map的一个子接口,是将键映射到值得对象,不允许键值重复,允许空键和空值;由于非线程安全, HashMap的效率要较 HashTable 的效率高一些.
HashTable 是线程安全的一个集合,不允许 null 值作为一个 key 值或者 Value 值;
HashTable 是 sychronize(同步化),多个线程访问时不需要自己为它的方法实现同步,而 HashMap 在被多个线程访问的时候需要自己为它的方法实现同步;

▷ HashMap原理

一. Hash表:

不考虑哈希冲突的情况下,仅需一次定位即可完成,时间复杂度为O(1),查找、新增、删除效率十分高。
数据结构的物理存储结构只有两种:顺序存储结构链式存储结构;在数组中根据下标查找某个元素,一次定位就可以达到,哈希表利用了这种特性,哈希表的主干就是数组,所以查询时,通过一个hash函数计算出存储下标,可以直接定位到要找的值,所以速度快;
如果两个不同的元素,通过哈希函数得出的实际存储地址相同怎么办?也就是说,当我们对某个元素进行哈希运算,得到一个存储地址,然后要进行插入的时候,发现已经被其他元素占用了,其实这就是所谓的哈希冲突(哈希碰撞)
哈希冲突如何解决呢?哈希冲突的解决方案有多种:开放定址法(发生冲突,继续寻找下一块未被占用的存储地址),再散列函数法,链地址法,而HashMap即是采用了链地址法,也就是数组+链表的方式.

二. HashMap实现原理
三. 重写equals方法需要重写hashCode算法

如果我们已经对HashMap的原理有了一定了解,这个结果就不难理解了。尽管我们在进行get和put操作的时候,使用的key从逻辑上讲是等值的(通过equals比较是相等的),但由于没有重写hashCode方法,所以put操作时,key(hashcode1)-->hash-->indexFor-->最终索引位置 ,而通过key取出value的时候 key(hashcode1)-->hash-->indexFor-->最终索引位置,由于hashcode1不等于hashcode2,导致没有定位到一个数组位置而返回逻辑上错误的值null(也有可能碰巧定位到一个数组位置,但是也会判断其entry的hash值是否相等,上面get方法中有提到。)
所以,在重写equals的方法的时候,必须注意重写hashCode方法,同时还要保证通过equals判断相等的两个对象,调用hashCode方法要返回同样的整数值。而如果equals判断不相等的两个对象,其hashCode可以相同(只不过会发生哈希冲突,应尽量避免)。

四. java8改进hashMap

▷ 为什么集合类不实现Cloneable和Serializable接口

克隆(cloning)或者序列化(serialization)的语义和含义是跟具体的实现相关的。因此应该由集合类的具体实现类来决定如何被克隆或者序列化

▷ Concurrenthashmap的实现(1.7和1.8)

前言

HashMap在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原数组的内容重新hash到新的扩容数组中,在HashMap扩容时,会改变链表中的元素的顺序。在多线程的环境下,存在同时其他的元素也在进行put操作,如果hash值相同,可能出现同时在同一数组下用链表表示,将元素从链表头部插入造成闭环,导致在get时会出现死循环,所以HashMap是线程不安全的。

1.7实现

ConcurrentHashMap的数据结构是由一个Segment数组和多个HashEntry组成,如下图所示:


结构图

Segment数组的意义就是将一个大的table分割成多个小的table来进行加锁,也就是上面的提到的锁分离技术,而每一个Segment元素存储的是HashEntry数组+链表,这个和HashMap的数据存储结构一样。

1.8实现

摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap

1.7和1.8的区别

上一篇 下一篇

猜你喜欢

热点阅读