java面试随笔总结
set map list
list 有序可重复
- Arraylist 基于动态数组实现,可随机get和set 查询效率高,线程不安全
- LinkedList 基于双向链表实现,增加删除不用大量移动元素,省时间,有其他更通用的方法getLast,removeFirst等等,可当做堆栈,队列,双向队列用。
map键值对键唯一,值不唯一。
- HashMap 使用对象的hashcode()进行快速查询
- LinkedHashMap 底层使用链表来维护内部次序,速度比HashMap稍慢一点,
- TreeMap 基于红黑树实现,得到的是排序的结果
set无序不可重复,位置由hashcode决定的位置是固定的。
- HashSet 底层是HashMap 支持null 使用hash算法存取对象,速度较快
- TreeSet 实现了SortedSet 接口能对对象排序
- LinkedHashSet 双向链表维护内部次序,底层使用LinkedHashMap 方法与HashSet相同,有hsahset的查询速度。
HashMap 和HashTable
都实现了Map Cloneable Sevializable接口
- HashMap实现 AbstractMap接口,可有一个键值为NULL,线程不安全多并发时不安全,需自增同步处理,或者使用ConcurrentHashMap (1.8之后使用CAS算法) 使用了同步锁,使用了fail-fast迭代器,当其他线程改变HashMap抛出ConcurrentModificationException异常,初始化大小为16,每次扩充的容量为原来的2倍,2的次幂大小便于位运算,侧重点在Hash的效率方面,底层用的是数组加链表,jdk1.8之后用的是数组链表红黑树(当链表的碰撞大于8时,或者或者总容量大于64时,结构转化为红黑树,除了添加效率高于其他一切)
- HashTable 线程安全,每个方法都用了synchronized 1.8之后也使用了fail_fast 初始化大小为11 每次扩充为原来的2n+1倍,侧重点是使Hash的结果更均匀,使得Hash冲突减小,使用的使除法运算所以效率低
多线程
①用户线程 ②守护线程
java线程中有两种线程:①用户线程 ②守护线程用户线程:平时用到的普通线程均是用户线程
守护线程:指在程序运行的时候在后台提供一种通用服务的线程,守护线程是为用户线程服务的,当有用户线程在运行,那么守护线程同样需要工作,当所有的用户线程都结束时,守护线程也就会停止
设置线程的Daemon为true,且必须在thread.start()之前设置Daemon线程中产生的新线程也是Daemon
守护线程不应该去访问固有资源,如进行读写操作(文件,数据库),因为守护线程是跟随用户线程的,当没有用户线程工作时,守护线程会立即结束
不适合用于输入输出或计算操作
适用于辅助用户线程场景,如GC,内存管理
当所有的用户线程结束时,守护线程就结束了,不会继续执行
死锁
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或造成的一种阻塞的现象
wait()与 sleep()的区别?
sleep()来自 Thread 类,wait()来自 Object 类;
调用 sleep()方法,线程不会释放对象锁。而调用 wait 方法线程会释放对象锁;
sleep()睡眠后不出让系统资源,wait 让其他线程可以占用 CPU;
sleep(milliseconds)需要指定一个睡眠时间到阻塞状态,时间一到会自动唤醒。而 wait()则是处于挂起状态需要配合 notify()
或者 notifyAll()使用唤醒到就绪状态。
wait()方法必须放在同步控制方法和同步代码块中使用,sleep()方法则可以放在任何地方使用。sleep()方法必须捕获异常,而wait()、notify()、notifyAll()不需要捕获异常。在sleep的过程中,有可能被其他对象调用他的interrupt(),产生InterruptedException。由于sleep不会释放锁标志,容易导致死锁问题的发生,因此一般情况下,推荐使用wait()方法。
GC
java 内存分配
- 静态(方法区):主要存储静态数据,全局变量,程序编译时存在
- 栈区:方法的局部变量的基本数据类型和引用存储于栈中,引用的对象实体存储于堆中。(属于方法中的变量,生命周期随方法而结束。)
- 堆区:成员变量全部存储与堆中(包括基本数据类型,引用和引用的对象实体)属于类,动态内存分配,类对象终究是要被new出来使用的这部分进行GC。
java 四种引用类型
- 强引用:不会让GC回收具有强引用的对象
- 软引用:内存空间不足时,才会被回收
- 弱引用:在GC时,一但发现,不管内存是否够都会被回收
- 虚引用:任何时候可被GC,发现有虚引用时检查与之有关联的队列,判断队列是否有该对象的虚引用,来了解对象是否可被回收。
垃圾回收机制?
什么时候回收:
可达性分析:对象引用抽象为树形,GCRoot为起点,往下搜索,搜索链称引用链,一个对象无法到达GCRoot时则不可用,被判定可回收。
引用计数法:给对象添加引用计数器,每当有地方引用时计数加一,反之失效时技术减一,当计数器为零时表示不被引用则可回收
回收方法
- 新生代 minorGC (局部变量):复制算法:内存分为两块,每次用其中一块,满之后将存活的对象按严格的顺序复制到另一块,把已使用的进行回收,可得到连续的空间,但是浪费了一半空间。
- 老年代 MajorGC (生命周期长的对象)标记-清除算法:遍历所有的GCRoot,分别标记可达和不可达的对象,后将不可达的对象进行回收,效率低得到的是不连续的空间。
- 分代算法 新建的对象存在新生代中,若新生代内存不够进行minorGC,释放掉不活跃的对象,不够则把部分活跃的对象复制到老年代,若换是不够进行MajorGC释放老年代,再不够会抛出OOM内存泄漏。
Assert 断言,Assertion程序中的一条语句,对一个boolean表达式进行检查,一个正确的程序必须保证这个boolean表达式的值为True,Assertion 用于保证程序最基本关键的正确性。
开发和测试时开启,软件发布后Assertion检查通常关闭。
String ,StringBuffer,StringBuilder
String 是字符串常量,创建不可改变,可共享,
StringBuffer 是字符串缓冲区,线程安全,内容可被修改,长度可被修改,
StringBuilder 字符串缓冲区,线程不安全,在单线程中使用效率比较高
JVM ClassLoader
Bootstrap CloassLoader 加载基础类 (resources.jar charset.jar rt.jar class)
Extonsion ClassLoader 加载扩展类
App ClassLoader 加载应用classPath中所有类
ClassLoader使用全盘负责委托机制
内存泄漏,溢出
内存泄漏:一个不在被程序使用的对象或者变量一直占据在内存中,GC无法进行回收,【长生命周期对象引用已经不需要的短生命周期对象,导致其无法进行GC】
原因
- 单例模式
- 非静态内部类创建静态实例
- 资源未关闭
可能导致内存溢出,可通过代码完善
内存溢出:申请内存时没有足够的空间共申请者使用,给Int 存Long
原因
- 代码不规范:
- 内存抖动,一次申请过多资源
ThreadLocal 与Synchonized区别
ThreadLocal ThreadLocal为解决多线程程序的并发问题提供了一种新的思路.当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。在ThreadLocal类中有一个Map(ThreadLocalMap),用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。
Synchonized同步机制采用了“以时间换空间”的方式,仅提供一份变量,让不同的线程排队访问
ThreadLocal采用了“以空间换时间”的方式。它通过为每个线程提供一个独立的变量副本,因此可以同时访问而互不影响
在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。
锁机制进行时间换空间,一个是存储拷贝进行空间换时间
Math
Math.round(),Math.ceil(),Math.floor()的区别
1.Math.round():根据“round”的字面意思“附近、周围”,可以猜测该函数是求一个附近的整数,看下面几个例子就明白。小数点后第一位<5正数:Math.round(11.46)=11负数:Math.round(-11.46)=-11 小数点后第一位>5正数:Math.round(11.68)=12负数:Math.round(-11.68)=-12 小数点后第一位=5正数:Math.round(11.5)=12负数:Math.round(-11.5)=-11总结:(小数点后第一位)大于五全部加,等于五正数加,小于五全不加。
2.Math.ceil():根据“ceil”的字面意思“天花板”去理解;例如:Math.ceil(11.46)=Math.ceil(11.68)=Math.ceil(11.5)=12Math.ceil(-11.46)=Math.ceil(-11.68)=Math.ceil(-11.5)=-11
**3.Math.floor():根据“floor”的字面意思“地板”去理解;**例如:Math.floor(11.46)=Math.floor(11.68)=Math.floor(11.5)=11Math.floor(-11.46)=Math.floor(-11.68)=Math.floor(-11.5)=-12