1. 操作系统
1.1 什么是操作系统?
操作系统就是用来管理硬件和软件资源的程序,它是硬件系统的核心,用来管理子程序,内存,资源供需的优先次序,控制输入输出设备,操作网络,文件系统等基本事务。提供与用户交互的界面。
1.2 什么是线程,什么是进程?
进程是系统资源分配的最小单元,而线程是CPU调度的最小单元,线程运行在进程中,进程可以包含多个线程,进程内,线程共享进程资源。进程之间不能共享资源。
2. JVM
2.1 JDK & JVM & JRE分别是什么以及它们的区别?
JRE Java运行时环境,包括jvm以及运行时的资源。
jdk包括了jre, 一堆Java工具,还有Java基础类库。
jvm是Java程序跨平台运行的核心,Java打包后的class文件就是运行在jvm里面,并被翻译成机器码。不同的操作系统有不同的jvm。
2.2 可以做GC root的对象
虚拟机栈中引用的对象
方法去静态属性引用对象
方法区常量池引用对象
本地方法栈jni引用对象
3. 面向对象
3.1 接口和抽象类区别
接口:
1) 接口是公开的,方法也是,默认不写修饰符
2) 没有方法体
3) 没有实例域和静态方法,可以有常量
4) 不能被实例化
5) 使用方式:被实现
抽象类:
1) 可以有私有变量和方法
2) 抽象的方法必须加abstract修饰符
3) 不能实例化
4) 使用方式:被继承
3.2 Java多态的实现机制是什么?
重载和重写
3.3 谈谈你对对象生命周期的认识?
如果从表层去看的话,我觉得对象的生命周期主要分创建阶段,应用阶段,不可视阶段,不可达阶段,回收释放阶段
先是代码里面定义类,然后通过强引用,软引用。。。进行应用阶段并在jvm的堆区创建对象,然后在超过对象的作用域后,对象不可见,也就可以被GC回收。不可达阶段,是不再有引用指向对象,这类就会被回收。然后就是被GC回收释放对象空间。
3.4 static关键字的作用
修饰成员变量,类加载时就被分配空间,可以通过类直接访问,存储在静态存储区。
修饰成员方法,类直接调用,不用new
单例
静态导入包,导入类中的静态方法。
4. NIO/BIO/AIO
BIO(IO)使用流,同步阻塞
NIO同步非阻塞,有个快递,你要去快递点查看快递有没有到。
AIO异步非阻塞,快递由快递员送上门。
NIO的特点:大文件处理效率很快,多路复用技术,一个线程监听多个io端口
4.1 读取一个txt文本文件乱码了,你觉得原因是什么
没有指定编码格式
5. 集合
Java 集合详解 https://blog.csdn.net/feiyanaffection/article/details/81394745
5.1 遍历map的方式:
entrySet,keyset
5.2 HashMap如何解决哈希碰撞
首先是根据hashcode找到对应位置,如果对应位置已存元素,那么就会通过equals进行判断,如果已存在就用新的值替换旧值
5.3 hashmap是如何散列元素的?
Hashcode &(length-1),自定义长度也要设置为2的n次方,散列更加均匀。
5.4 ConcurrentHashMap如何实现并发访问的
hashmap线程不安全,hashtable效率低,竞争一把锁。所以用了分段锁技术,对数据进行分段加锁的方式。所以在效率上也就有所改善。首先是segment数据,每一个segment是一个reentrantlock,并管理一个hashentry数组,默认16个,需要两次hash运算找到对应元素。
5.5 LinkedHashMap原理
有序map, 默认按插入顺序
5.6 Collection 和 Collections的区别
1)是集合框架接口,子类有。。
2)是集合工具类,提供很多静态方法
6. 泛型
6.1 泛型种extends和super关键字的区别
Extends限制对象上界,那么返回对象我们就可以直接申明为上界可以读取
Super 限制对象下界,适合写入类型,好比方法参数申明为一个接口类型。
7. JVM
7.1 Java内存结构 & 内存模型
内存结构:堆栈,方法区
内存模型:针对多线程而言,主内存,每个线程对应的本地内存。
7.2 Java虚拟机是如何加载一个类的
加载:读取字节流,创建类,由类加载器完成;
链接:
1) 验证:对加载的类校验是否符合虚拟机约束条件。
2) 准备:给(类变量)静态字段分配内存并赋初始值,构建类的数据结构。
3) 解析:将符号引用变成直接引用。
初始化:父类静态变量静态快初始化-》子类静态变量静态快初始化-》父类实例变量和代码块-》父类构造函数-》子类实例变量代码块-》子类构造函数
7.3 谈谈类加载器
jvm会用不同的类加载器去加载不同的类,从而保证jvm中只有一个这样的类。
类加载是有一个父类委托机制,也就是说用户实现一个类加载的话,首先是将加载请求委托给父加载器,然后再向上委托知道顶端,然后顶端去对应位置寻找,没有就交给子类一直乡下传递。
8. 其他
8.1 为什么不能用“+”的方式进行拼接String
因为编译之后+对应还是用stringbuilder去实现,就会产生很多builder中间对象
8.2对依赖注入的理解
依赖的类对象以传参的方式注入,构造方法注入,set注入,注解注入
8.3 分派的理解
重载和重写
9. 多线程
9.1 乐观锁悲观锁
悲观锁,就是读的时候也加锁,总是预期最坏的情况。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
乐观锁,总是假设最好的情况,读的时候不会上锁,写的时候会判断是否有其他人在更新,对应CAS算法。对应atomic包下。适用于读多写少的场景。
9.2 线程上下文切换
线程加载到CPU执行以及放弃CPU到存储状态的切换过程。会耗费系统资源
如何减少上下文切换。
尽量无锁并发编程,使用线程分段访问数据,类似concurrentHashMap
CAS算法,不用加锁。https://www.jianshu.com/p/377666236271
使用最少线程。
协程,单线程调度多任务。
9.3 创建线程内存分配
JVM初始运行的时候都会分配好Method Area(方法区)和Heap(堆),而JVM 每遇到一个线程,就为其分配一个Program Counter Register(程序计数器), VM Stack(虚拟机栈)和Native Method Stack (本地方法栈),当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。一个线程放弃时间片后需要保存状态,就需要程序计数器保存执行位置,调用方法的信息保存到栈中。
9.4 Synchronized与lock的区别
lock更加灵活;lock需要手动释放锁,sync自动释放锁;lock可以实现公平锁,判断是否获取到锁,并且可以放弃等锁。lock.tryLock尝试获取锁,规定时间未获取到锁就放弃。
9.5 如何避免死锁?
规定获取锁的顺序,对于一个线程,如果需要获取多个锁,必须按照规定顺序获取锁,A、B、C,对于每一个线程都必须按这个顺序获取锁。
加锁时限,trylock来尝试获取锁。
9.6 多线程操作文件
利用filechannel trylock来获取锁,如果文件锁被其他线程持有,直接返回null并抛出异常
9.7线程间共享数据
1) 利用wait和notify去控制变量的修改先后关系。从而保证变量的线程安全。
2) volatile控制可见性
3) Handler
4) 管道流pipe
9.8 线程死锁原因,举个例子
本质在于多个线程竞争资源锁,如果竞争过程出现闭环,就会死锁
sync锁嵌套使用。
9.9 如何停止掉一个线程
通过interrupt,设置标志位
9.10 什么是公平锁&非公平锁&区别
公平锁,线程获取锁的顺序和调用lock的顺序一样。会增加时间开销
非公平锁,获取顺序与调用lock的顺序无关。
9.11 线程状态切换详解
https://www.cnblogs.com/hejing-swust/p/8038263.html
9.12 线程池详解
https://www.cnblogs.com/exe19/p/5359885.html
10 枚举
10.1 为什么枚举比int多占两倍?
因为枚举编译之后也是类,继承子enum,内部实现是多个静态变量对象,并且用一个数组去存这些对象,所以占更多空间。
11.算法
11.1 排序算法稳定性。
https://blog.csdn.net/guoke2017/article/details/80929134
稳定性是什么?就是键值相等的两个元素,先后顺序在排序之后不会变化。
稳定性的作用是什么?比如信息流两条热门置顶资讯,你在重新排序之后,稳定性的算法,就不会针对都是热门标签重新排序,所以会保持原先的顺序。
稳定性的排序算法:基数排序,直接插入排序,冒泡排序,归并排序。
不稳定的排序算法:桶排序,希尔排序,快速排序,简单选择排序,堆排序
12.其他
12.1 String、StringBuffer、StringBuilder有什么区别?
https://baijiahao.baidu.com/s?id=1629804867201303563&wfr=spider&for=pc
持续更新中。。。
网友评论