面经-基础篇-一

本文最后更新于:2021年3月28日 下午

以下内容并非博主亲身经历的面试问题,只是对网络中的面经做一个总结、记录。

1.01 JAVA中的几种基本数据类型是什么,各自占用多少字节?

JAVA有八种基本数据类型

  • 整型
    • byte 、 short 、 int 、 long
  • 浮点型
    • float 、 double
  • 字符型
    • char
  • 布尔型
    • boolean
数据类型占用字节默认值封装类
byte(字节型)10Byte
short(短整形)20Short
int(整形)40Integer
long(长整形)80.0lLong
float(浮点型)40.0fFloat
double(双精度浮点型)80Double
char(字符型)2\u0000(空格)Character
boolean(布尔型)Boolean

boolean在java规范里并没有规定大小;
网上说的大小有很多,比如1个bit(1/8个字节)、1个字节、4个字节;
我更倾向于4个字节,因为boolean类型会被编译为int类型,等于是说JVM里占用字节和int完全一样,int是4个字节,所以boolean也是4字节

1.02 String类能被继承吗,为什么?

不能 因为String被关键字final修饰。

1.03 final的用途

final是一种修饰符,是一种规定,可以用于修饰类、成员方法和成员变量

  • final所修饰的类:不能被继承,不能有子类
  • final所修饰的方法:不能被重写
  • final所修饰的变量:是不可以修改的,是常量

1.04 String,Stringbuffer,StringBuilder的区别?

类型
值是否可变
线程安全
常用
描述
String不可变String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间
StringBuffer可变线程安全多线程操作字符串StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量
StringBuilder可变线程不安全单线程操作字符串可变类,速度更快

1.05 ArrayList和LinkedList有什么区别?

  • ArrayList 查询快
  • LinkedList 增删快
  • 因为ArrayList底层是一个数组,所以查询快;LinkedList底层是一个链表,所以增删快。

ArrayList与LinkedList
如图所示,假设有一int类型类型的数组,每个int对象都有内存大小,占用4个字节。如果我们要查找第3个对象,可以通过(3-1)*4=8,故9到12字节就是我们要找的对象。是不是很快呢?而链表却不能做到这样的效率。如上图,我们要找到A3,必须先找到A2,要想找到A2,又必须先找到A1;这样的查找效率会大大降低。
ArrayList与LinkedList插入图解
如上图所示,数组的插入也相当的浪费效率;如果要在数组内的某一个位置进行插入,需要先将插入位置的前面复制一份,然后在新的数组后面添加新的元素,最后将旧的数组后半部分添加的新的数组后面;而在链表中插入就变得相当简单了,比如我要在A1和A2中插入A10,只需定位到A1的指针和A2的数据即可,将A1的指针指向A10的值,将A10的指针指向A2的值,A10就插入进了链表。

1.06 讲讲类的实例化顺序,比如父类静态数据,构造函数,字段,子类静态数据,构造函数,字段,当new的时候,他们的执行顺序。

  1. 先静态: 先静态,后非静态
  2. 先父后子: 先父类同级,后子类同级
  3. 优先级: 字段 > 带参构造函数 > 无参构造函数 > 普通函数
  4. 同级: 从上到下依次执行

1.07 用过哪些Map类,都有什么区别,HashMap是线程安全的吗,并发下使用的Map是什么,他们内部原理分别是什么,比如存储方式,hashcode,扩容,默认容量等。

常见的Map类有 HashMapConcurrentHashMapHashTableLinkedHashMapTreeMap

并发下常使用 ConcurrentHashMap

类型
存储方式
是否允许空值
HashMap根据键的HashCode值存储数据最多只允许一条记录的键为 Null;允许多条记录的值为 Null
HashTable根据键的HashCode值存储数据键或值都不允许为 Null
LinkedHashMap根据键的HashCode值存储数据同 HashMap
TreeMap根据键的HashCode值存储数据不允许键为Null;允许多条记录的值为 Null
类型默认容量扩容机制是否有序
HashMap16(必须为2的整数次幂)容量变为原来的2倍
HashTable11(不要求底层数组的容量一定要为2的整数次幂)容量变为原来的2倍加1
LinkedHashMap容量没有限制-默认是数据插入顺序
TreeMap容量没有限制-默认是key升序
类型
线程安全
优缺点
HashMap很快的访问速度,而且在Map中插入、删除和定位元素,HashMap 是最好的选择。
HashTable它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢
LinkedHashMapLinkedHashMap是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现,它还可以按读取顺序来排列,像连接池中可以应用。
TreeMapTreeMap取出来的是排序后的键值对。但如果要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。

1.08 JAVA8的ConcurrentHashMap为什么放弃了分段锁,有什么问题吗,如果你来设计,你如何设计。

弃用原因:

  • 加入多个分段锁浪费内存空间。
  • 生产环境中, map 在放入时竞争同一个锁的概率非常小,分段锁反而会造成更新等操作的长时间等待。
  • 为了提高 GC(垃圾回收) 的效率。。
  • 为了降低锁的粒度,提高性能。

jdk8 放弃了分段锁而是用了Node锁,,并使用CAS操作来确保Node的一些操作的原子性,取代了锁。

1.09 ConcurrentHashMap(JDK1.8)为什么要使用synchronized而不是如ReentranLock这样的可重入锁?

  • 减少内存开销
    假设使用可重入锁来获得同步支持,那么每个节点都需要通过继承AQS来获得同步支持。但并不是每个节点都需要获得同步支持的,只有链表的头节点(红黑树的根节点)需要同步,这无疑带来了巨大内存浪费。
  • 获得JVM的支持
    可重入锁毕竟是API这个级别的,后续的性能优化空间很小。
    synchronized则是JVM直接支持的,JVM能够在运行时作出相应的优化措施:锁粗化、锁消除、锁自旋等等。这就使得synchronized能够随着JDK版本的升级而不改动代码的前提下获得性能上的提升。

1.10 有没有有顺序的Map实现类,如果有,他们是怎么保证有序的?

TreeMap和LinkedHashmap都是有序的

TreeMap默认是 key升序 ,也可以自定义排序规则:要实现Comparator接口

LinkedHashmap默认是数据 插入顺序

TreeMap 底层存储结构是二叉树,二叉树的中序遍历保证了数据的有序性

LinkedHashMap 底层存储结构是哈希表+链表,链表记录了添加数据的顺序

0.0 参考链接


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!