面试题
(先分享一个优秀博主@ThinkWon的笔记,大家一定多多支持这个博主!!!,本篇内容陆续更新中。。。。)
序号 | 内容 | 链接地址 |
---|---|---|
1 | Java基础知识 | https://thinkwon.blog.csdn.net/article/details/104390612 |
2 | Java集合容器 | https://thinkwon.blog.csdn.net/article/details/104588551 |
3 | Java异常 | https://thinkwon.blog.csdn.net/article/details/104390689 |
4 | 并发编程 | https://thinkwon.blog.csdn.net/article/details/104863992 |
5 | JVM | https://thinkwon.blog.csdn.net/article/details/104390752 |
6 | Spring | https://thinkwon.blog.csdn.net/article/details/104397516 |
7 | Spring MVC | https://thinkwon.blog.csdn.net/article/details/104397427 |
8 | Spring Boot | https://thinkwon.blog.csdn.net/article/details/104397299 |
9 | Spring Cloud | https://thinkwon.blog.csdn.net/article/details/104397367 |
10 | MyBatis | https://thinkwon.blog.csdn.net/article/details/101292950 |
11 | Redis | https://thinkwon.blog.csdn.net/article/details/103522351 |
12 | MySQL | https://thinkwon.blog.csdn.net/article/details/104778621 |
13 | 消息中间件MQ与RabbitMQ | https://thinkwon.blog.csdn.net/article/details/104588612 |
14 | Dubbo | https://thinkwon.blog.csdn.net/article/details/104390006 |
15 | Linux | https://thinkwon.blog.csdn.net/article/details/104588679 |
16 | Tomcat | https://thinkwon.blog.csdn.net/article/details/104397665 |
17 | ZooKeeper | https://thinkwon.blog.csdn.net/article/details/104397719 |
18 | Netty | https://thinkwon.blog.csdn.net/article/details/104391081 |
19 | 架构设计&分布式&数据结构与算法 | https://thinkwon.blog.csdn.net/article/details/105870730 |
1.排序算法
名称 | 平均时间复杂度 | 最坏时间复杂度 | 最好时间复杂度 | 是否稳定 |
---|---|---|---|---|
插入排序 | n^2 | n^2 | n | 稳定 |
冒泡排序 | n^2 | n^2 | n | 稳定 |
归并排序 | nlogn | nlogn | nlogn | 稳定 |
选择排序 | n^2 | n^2 | n^2 | 不稳定 |
快速排序 | nlogn | n^2 | nlogn | 不稳定 |
堆排序 | nlogn | nlogn | nlogn | 不稳定 |
1.相关概念:
1.稳定排序:A=B且排序前A在B前面,排序后A还在B前面
2.不稳定排序:A=B且排序前A在B前面,排序后A还在B后面
2.具体实现
1.冒泡排序:
public void Bubblesort(int [] arr){
//i从后往前用来确定每一次最后的位置也就是把最大值上浮到最后一位
for(int i=arr.length;i>0;i--){
//从前开始两两相互比较
for(int j=0;j<i;j++){
if(arr[j]>arr[j+1]){
int tem=arr[j];
arr[j]=arr[j+1];
arr[j+1]=tem;
}
}
}
}
2.归并排序
public int[] mergeSort(int [] arr){
int len=arr.length;
if(len<2) return arr;
int mid=length/2;
//二分数组
int[] left= Arrays.copyOfRange(arr,0,mid);
int[] right= Arrays.copyOfRange(arr,mid,len);
//内部递归二分数据,然后合并二分后的数组
return merge(mergeSort(left),mergeSort(right));
}
public int[] merge(int[]left,int[] right){
int[] result= new int[left.length+right,length];
//index是result的下标,i是left数组的下标,j是right数组的下标
for(int index=0, i=0,j=0;index<result.length;i++){
//左数组第一个值小于右数组,将该值加入结果
if(left[i]<right[j]){
result[index]=left[i];
i++;
//左数组第一个值大于右数组,将该右数组第一个值加入结果
}else if(left[i]>right[j]){
result[index]=right[j];
j++;
//左数组全部添加进结果集后,只加右数组
}else if(i>=left.length){
result[index]=right[j];
j++;
//右数组全部添加进结果集后,只加左数组
}else if(j>=right.length){
result[index]=left[i];
i++;
}
}
return result;
}
3.选择排序
public void selectSort(int [] arr){
for(int i= 0;i<arr.length-1;i++){
int minIndex=i;
for(int j=i+1;j<arr.length-1;j++){
if(arr[min]<arr[j]){
min=j;
}
}
int tem =arr[min];
arr[min]=arr[i];
arr[i]=tem;
}
}
4.快速排序
public void quickSort(int[]arr,int low,int high){
if(low<high){
int index= getIndex(arr,low,high );
quickSort(arr,low,index-1);
quickSort(arr,low,index-1);
}
}
public int getIndex(iny[] arr,int low,int high){
int tem=arr[low];
while(low<high){
//从后向前找比基准值小的,交换
while(low<high&&arr[high]>=tem){
high--;
}
arr[low]=arr[high];
//从前向后找比基准值大的,交换
while(low<high&&arr[low]<=tem){
low++;
}
arr[high]=arr[low];
}
//将基准值赋值到中间是的,左小又大
arr[low]=tem;
return low;
}
改进:
1.切分数组较小时该用插入排序性能更好
2.三数曲中,将三个元素的剧中的元素作为切分元素
3.三向切分,对于有大量重复元素的数组,将数组切分成<=>三部分
5.堆排序
//小顶堆
Queue<Integer> list= new PirorityQueue<Integer>();
//大顶堆
Queue<Integer> list= new PirorityQueue<Integer>(
//在构造函数中传入自定义比较器
new Comparator<Integer>(){
public int compare(Integer o1.Integer o2){
return o2-o1;
}
}
);
2.TopK问题:
1.全排序:选取第k个
2.局部排序:冒泡,冒出k个最大
3.不排序:
1.堆排序,构造K维大/小顶堆,小顶堆保证里面是k个最大,大顶堆保证里面是k个最小
2.快排:选择切分点,刚好盖切分点右边有k-1个大于它的,他就是k大
基础部分
1.值传递与引用传递
java都是值传递
1.基本类型传递的是值的拷贝,修改不影响原本值
2.引用类型传递的是对内存中同一对象的引用的拷贝,也就是拷贝引用与原本引用指向的的是同一个堆上的对象,也就是一个一根绳子系气球,现在复制一根绳子在系上同一个气球,传入的都是同一对象,对其操作对其他引用都可见。
交换的是拷贝引用指向的对象,原先的引用不冲突,但如果进行修改,那么原先的引用也会被修改
2.hashcode与equals
==判断基本类型是否相等,比较的是内存地址
equals有两种情况:
1.未覆盖:判断的是同一对象,比较的是内存地址是否相等
2.覆盖后:判断内容是否相同,比较的内存地址中的内容是否相同
hashcode:就是获取哈希码,每个对象有唯一的哈希码,在哈希表中可以快速定位
//为什么要有hashcode?
比如在hashset中加入一个对象,会先判断对象是否存在,也就是比较hashcode值,没有相等的hashcode值直接插入,有过有相同的,还要调用equals来检查hashcode相同的相同的对象,内容是否一样,如果一样拒绝插入
//**所以在equals覆盖过之后,hashcode必须也要被重写,不重写hashcode两个对象无论如何都不会相等,**
//**因为equals相等的前提是hashcode然后比较内容是否相同,hashcode不相同,两个对象永远也无法相等。**
两个对象相等,哈是从的一定相等,equals返回true
hashcode相等,两个对象不一定相等
3.IO流
- InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
- OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
集合部分
1.继承关系
spring获取上下文:
1.通过配置文件,注解配置累获取:
ClassPathXmlApplicationContext:类路径
FileSystemXmlApplicationContext:文件系统,磁盘路径
AnnotationConfigApplicationContext:主机配置累=类
2.通过WebApplicationUtils工具类获取,依赖servlet容器
3.创建工具类实现ApplicationContextAware方法,记得在配置文件注册一下
Spring获取bean:
上述三种+
继承抽象类ApplicationObjectSupport
注解:继承Annotation接口的接口,用于标注
集合
1.ArrayList:
1.数组实现,增删慢慢,超快,容量不够需要扩容1.5倍
2.初始化时为传入容量是,默认是10,但是要注意,初始化时都是创建的空数组,只有当第一次add插入时,才会被扩容至10
3.大数据插入时,自动扩容太慢,主要是因为要开辟数组复制移动数据,除传入初始容量外,还可以调用ensureCapacity()方法传入扩展容量
3.LinkedList:
1.双向链表,还实现Deque接口的许多方法,可以被用作队列、栈等,不支持随机访问,只能顺序访问,所以查找速度慢,但是增删速度快,而且不需要扩容
3.HashMap:
1.成员变量:
初始容量:16
负载因子:0.75
扩容阈值:16*0.75=12
转红黑树阈值:8
2.构造方法:
传入自定义初始容量,并不直接传入而是交友tablesizefor函数进行转换转成最靠近的2的N次方的最大值
3.put:
利用hashcode获取hash值,在(n-1)&hash获取下标
如何获取hash值:
1.获取高位 h>>>16获取高16位不变
2.用高位与原hashcode异或,减少碰撞,也就是,高16位不变,低16位与高16位异或
3.jdk1.7也类似但总动扰动4次,性能差一点
4.resize
两次
1.数组空或null 执行
2.键值对数量超过阈值或重新扩容
如何扩容?扩容两倍,移动元素
jdk1.7要重新计算hashcode,jdk1.8直接根据原来的位置判断要么不动,要么移动到原位置+原数组大小的位置
4.TreeMap
底层是红黑树
1所有结点不是黑就是红
2.根节点是黑
3.叶子结点黑
4.红色的孩子必位黑色
5.任意结点到叶子结点的所有路径上包含的相同数目的黑色结点