- 面向对象三大特征
封装、继承、多态 - i和i的区别
一个是先获得 i 的值再++, 一个是先++再获得 i 的值 - 重写和重载的区别
重写条件:继承、向上转型 ?
重写是指一个子类中定义一个和父类方法名和参数相同的方法从而覆盖从父类中继承过来的方法。
重载是在一个类中,存在方法名相同,但是参数类型、顺序、数量不尽相同的方法。 - 接口和抽象类的区别
一个类可以实现多个接口,但不能继承多个抽象类
抽象类可以有实例方法,接口只能写抽象方法 ==
和equals的区别==
比较的是HashCode的值,equals 比较的是值- 为什么重写equals还要重写hashcode
在使用Map集合使用put方法时,不仅会判断两个对象值相等还会判断两个对象的hash值是否相等,如果只是重写equals方法,那么调用put时,可能两个对象通过equals比较相等,但是hash不相等,map集合也认为是不同的元素。
- 线程的创建方式?
继承Thread类;实现Runnable接口 ; - 线程池了解过吗?线程池的七个核心参数
corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler
corePoolSize 线程池核心线程大小
maximumPoolSize 最大线程数
keepAliveTime 空闲线程存活时间
unit 空闲线程存活时间单位
workQueue工作队列
ArrayBlockingQueue
LinkedBlockingQueue
SynchronousQueue
PriorityBlockingQueue
threadFactory 线程工厂
handler 拒绝策略
- 如果核心线程被占用了,当有新的请求进来会发生什么?
如果线程池中的线程数小于最大线程数,那么根据工作队列的不同采取不同的措施
如果是基于链表的无界阻塞队列,不会去创建新线程,其他的工作队列会创建新线程直到最大线程数
如果已经达到最大线程数,那么会根据拒绝策略执行不同的操作。
- 拒绝策略有哪些?如果我们用了无界队列的话有什么坏处?
CallerRunsPolicy 直接执行被拒绝任务的run方法,除非线程池已经shutdown,则直接抛弃任务
AbortPolicy 直接丢弃任务抛出异常
DiscardPolicy 直接丢弃任务什么也不做
DiscardOldestPolicy 出队首,尝试进队尾
无界队列会存入该队列,不会去创建线程
- 熟悉JVM。JVM的架构?
JVM 的主要组成部分包括类加载器、运行时数据区、执行引擎、本地库接口
各组件的作用:首先类加载器将Java代码转换为字节码,运行时数据区把字节码加载到内存中,但字节码文件只是JVM的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎,将字节码翻译成底层系统指令,再交由CPU去执行,而这个过程需要调用其他语言的本地方法库接口,来实现整个程序的功能。 - class文件的加载过程
Java类加载过程:加载、验证、准备、解析、初始化
加载:获取类的二进制字节流,并将类的信息存储到方法区中
验证:验证类的字节流中的信息是否符合虚拟机的要求,包括:文件格式验证、元数据验证、字节码验证、符号引用验证
准备:为类中的 static 变量分配(方法区中的)内存并赋初始值(如果是final修饰的,则按表达式初始化))
解析:虚拟机将常量池中的符号引用替换为直接引用的过程
初始化:执行类的构造器的过程 - 双亲委派的过程
当一个类加载时,他会先尝试让父类加载,并不断递归这个操作,到达启动类加载器,当父类加载器不能加载时,子类才会尝试去加载这个类。 - JVM的内存结构
JVM的运行时数据区包括:Java堆、方法区、虚拟机栈、本地方法栈、程序计数器
程序计数器:一块较小的空间,是线程私有的,指向方法区中的方法字节码,用来存储指向下一个指令的地址。
Java虚拟机栈: 描述的是Java方法执行的内存模型。每个方法运行的同时都会创建一个栈帧,存储局部变量表、操作数栈、动态链接、方法出口等。每个方法从调用到执行完成的过程,都对应一个栈帧从入栈到出栈的过程。他是每个线程私有的,生命周期和线程相同。
本地方法栈:和Java虚拟机栈的功能类似,但是本地方法栈为Native方法服务。
Java堆:存放大部分的对象实例,被所有线程共享,是垃圾回收的主要区域。
垃圾回收算法:标记-清除法、标记-复制法、标记-整理法
方法区:存储虚拟机已经加载的类的信息、常量(final)、静态变量static、即时编译器编译后的代码等,所有线程共享的区域。
运行时常量池是方法区的一部分。 - new String(“aa”); 创建了几个对象? 为什么
如果这个字符串在字符串常量池中不存在,那么就会创建两个对象。
一个在堆中,一个在字符串常量池中 String被final修饰,了解final的原理吗?
GC了解多少
垃圾回收算法有标记-清除法、标记-复制法、标记-整理法
垃圾收集器判断对象是否存活的算法:引用计数法、可达性分析算法- 什么对象会进入到老年代
长期存活的对象和大对象 - GMS和G1的区别
G1 与 GMS 垃圾收集器的区别:
① CMS 在老年代产生了内存碎片,导致对象的内存分配是采用了空闲链表的方式。G1 回收的内存是连续的,所以内存分配的方式是碰撞指针。
② G1 和 GMS 的内存模式是完全不一样的。G1 是以 Region 为单位进行内存回收,即将内存划分成一个个固定大小的 Region,每个 Region 属于Eden、Survivor、Old 或者 Humongous。GMS 采用传统的内存划分,将整个 Heap 分为 Eden、Survivor 和 Old。 - 如何进行JVM调优
todo - HashMap的实现原理?是不是线程安全的?不安全表现在哪里
JDK1.7 :Entry数组 + 链表
JDK1.8:Node数组+链表/红黑树
不是线程安全的
主要是多线程同时 put 时,如果同时触发了 rehash 操作,会导致 HashMap 中的链表中出现循环节点,进而使得后面 get 的时候,会死循环。 - 优先队列用过没有?大顶堆和小顶堆实现过吗?
优先队列的底层实现是堆(最大堆、最小堆)
堆的特点:
1.完全二叉树
2.每个父节点的值都必须大于等于或小于等于 子节点的值
3.往堆中插入和删除一个元素的试卷复杂度都是O(log n)
- 手写一个归并排序
#include<iostream>
using namespace std;
const int N = 200;
int tmp[N];
int a[N]={2,4,5,1,3},n;
void merge_sort(int l,int r)
{
if(l >= r) return;
int mid = l+r>>1;
merge_sort(l,mid);
merge_sort(mid+1, r);
int i = l, j = mid+1, k = 0;
while(i<=mid && j<=r){
if(a[i] < a[j]){
tmp[k++] = a[i++];
}
else{
tmp[k++] = a[j++];
}
}
while(i<=mid) tmp[k++] = a[i++];
while(j<=r) tmp[k++] = a[j++];
for(int i=l,j=0; i<=r&&j<k; ++i,++j){
a[i] = tmp[j];
}
return ;
}
int main()
{
n = 5;
merge_sort(0, n-1);
for(int i=0; i<n; ++i) cout<<a[i]<<' ';
cout<<endl;
return 0;
}
- 反转链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head==NULL) return NULL;
ListNode* prev = NULL;
ListNode * ne = head;
while(ne!=NULL){
ListNode * t = ne->next;
ne->next = prev;
prev = ne;
ne = t;
}
return prev;
}
};
- 线程安全的单例模式
public class SingleTest {
public SingleTest(){
}
private final static SingleTest SINGLE_TEST = new SingleTest();
public static SingleTest getInstance(){
return SINGLE_TEST;
}
}
- 上下文切换的理解,操作系统怎么实现上下文切换
上下文切换是指内核在CPU上对进程或者线程进行切换。上下文切换过程中的信息被保存在进程控制块(PCB)中。上下文切换的信息会一直保存在CPU内存中,直到被再次使用。
上下文切换的原理:当发生任务切换时,保存当前任务的寄存器到内存中,将下一个即将要切换过来的任务的寄存器状态恢复到当前CPU寄存器中,使其继续执行。 - 怎么减少并发编程中的上下文切换呢?
- 无锁并发编程。多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁。
- CAS算法。Java的Atomic包使用CAS算法来更新数据,不需要加锁。
- 使用最少线程,避免创建不需要的线程。
- 协程:在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换。
————《Java并发编程的艺术》
- CAS的原理
CAS是比较并交换的意思,CAS有三个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值和内存中的值相同时,将内存中修改为B,否则什么也不做。 - synchronized的锁升级策略
- 进程和线程的区别
进程是操作系统资源分配的基本单位
线程是CPU调度的最小单位
线程是进程的一部分,共享进程的资源,被称为轻量级进程 - 进程间的通信方式、线程间的通信方式
进程间的通信方式:匿名管道、有名管道、信号、消息队列、信号量、共享内存、套接字
线程间的通信方式:互斥量、信号量、事件 - TCP协议
- TCP和UDP的区别,TCP怎么保证可靠的
TCP是面向连接的、可靠的、用字节流传输
UDP是无连接的、不可靠、用数据报文段传输
TCP通过校验和、流量控制、拥塞控制、超时重传、ARQ协议保证可靠传输
TCP将大数据分割成几个小块发送 - TCP的滑动窗口了解吗
TCP是用滑动窗口来实现流量控制,接收方确认报文段的窗口字段可以影响发送方窗口的大小。 - ping命令的底层
ICMP协议 - OSI七层模型
从下到上:物理层、数据链路层、网络层、运输层、会话层、表示层、应用层
TCP/IP五层协议: 网络接口层、网际层、运输层、应用层 - Spring IOC和AOP
Spring IOC控制反转,是指将创建对象的控制权,交由Spring框架来管理。
AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。 - Spring如何解决循环依赖的?
- Spring的事物原理,隔离级别;mysql使用的哪个隔离级别
- MYSql有没有幻读问题?怎么解决的?
- select * from table where a=x and b>x and c <x 怎么建立索引?
- InnoDB引擎的B+ Tree树结构了解吗?它和B树的区别?
- token的组成?
- 在项目中使用redis的原因是什么?哪里使用redis?统一缓存是如何实现的?怎么保证缓存一致性?
- 如果有百万并发你如何应对?
- 秒杀系统十分常见?你怎么设计秒杀系统
- 平常遇到的技术难点?案例?
- 平常你怎么学习的?看什么书?