1.JDK、JRE、JVM三者的关系和区别
1.首先来说JDK是JAVA中的开发工具包,提供JAVA的开发环境和运行环境;
2.其次JRE是JAVA中的运行环境,为JAVA的运行提供所需的环境;
3.最后JVM指的是虚拟机,JAVA代码一次编译导出运行靠的就是JVM。
2.==和equals的区别
==: 对于基本类型来说,比较的是值,对于引用类型来说,比较的是地址。
equals:本质上就是==,只不过是String和Integer等重写了equals方法,用来比较值。
3.两个对象的hasCode()相同,则equals一定为true吗?
不一定,两个对象的hashCode ()相同,equals不一定为true。
因为hashCode ()相等,表示两个键值对的哈希值相等,然而哈希值相等并不能得出两个键值对相等。
4.final在java中的作用
final修饰的类叫做最终类,不能被继承,
final修饰的方法不能被重写,
final修饰的变量叫做常量,常量必须初始化,且之后不能再修改。
5.java中的Math.round(-1.5)等于多少
等于-1,四舍五入向上取整
6.String属于基本数据类型吗
不属于。
基本数据类型有8种,分别是int,short,long,byte,char,float,double,boolean
7.java中操作字符串有哪些类,他们之间的区别是?
操作字符串的类有三种,分别是String,StringBuffer,StringBuilder
String是不可变的对象,每次对String的操作实际是创建了新的对象,然后将指针指向新的对象
StringBuffer和StringBuilder是可以在原有对象上自由操作的对象
StringBuffer和StringBuilder的区别在于前者是线程安全的,后者是线程非安全的,故StringBuilder的性能高于StringBuffer
StringBuffer是线程安全的原因是因为StringBuffer对象由synchronize修饰
8.String str=“123”,和String str = new String (“123”)的区别
前者是将str的地址指向常量池中"123"的对象,后者是在堆内存中创建一个新的对象
9.如何将字符串反转
使用StringBuilder或者StringBuffer中reverse ()方法。
10.String类的常用方法
indexOf ():返回指定字符的索引
charAt ():返回指定索引处的字符
replace ():替换字符串
trim ():去掉字符串两端的空格
split ():按照指定字符或者字符串切割字符串,返回数组
length ():返回字符串长度
substring():截取字符串
equals ():比较字符串
toLowerCase ():转小写
toUpperCase ():转大写
11.抽象类必须要有抽象方法吗?
抽象类不是必须要有抽象方法
12.普通类和抽象类的区别
普通类不能包括抽象方法,抽象类可以包括抽象方法
抽象类不能直接实例化,普通类可以直接实例化
13.抽象类可以使用final修饰吗
不可以,定义抽象类的初衷就是让其他类继承,如果定义为final就不能被其他类继承
14,接口和抽象类的区别
抽象类的子类由extends来继承,接口的实现类由implements来实现
抽象类可以有构造函数,接口不可以
抽象类可以有main方法,接口不可以
对于子类来说只可以继承一个抽象类,但可以实现多个接口
接口中的方法默认用public修饰,抽象类中的方法可以是任意修饰符
15.java中io流分为几种
按功能分为输入流和输出流
按类型分为字节流和字符流
16.List,Set,Map之间的区别
List和Set都是实现了Collection接口的集合,Map是一个键值对
List中的元素可以重复,Set和Map中的元素不可以重复
List是有序的,Set是无序的
List可以利用递归逐一遍历,也可以利用下标直接定义,set只能利用递归逐一遍历
17.HashMap和TreeMap的区别
HashMap更方便于对Map的插入,定位,删除元素的这类操作
而TreeMap方便于对有序的key集合的遍历
18.HashMap的实现原理
HashMap是基于哈希表的Map接口的非同步实现,此实现提供所有可选的映射操作,并允许使用null值和null键,但不保证映射的顺序。
HashMap是一个数组和链表的结合体。
当我们往hashMap中put数据时,首先根据key的hashcode重新计算hash值,根据hash值得到这个元素在数组中的位置,如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素将以链表的形式存放,新加入的放入链头,最先加入的放入链尾,如果该位置上没有其他元素,直接把新加入的元素放在该位置。
19.HashSet的实现原理
HashSet底层由HashMap实现
HashSet的值存放于HashMap的key上
HashMap的值统一为PRESENT。
20.ArrayList和LinkedList的区别
前者底层是数组结构,支持随机访问
后者底层是双向循环链表,不支持随机访问
21.常见三种排序
1.冒泡排序
/**
* 冒泡排序
* 冒泡排序就是从前到后遍历选出最大值放到最后一个,
* 然后在遍历剩下的找出剩下中最大的放到倒数第二个,
* 依次直至遍历到最后一个,也就是最小的放到第一个,使其有序。
*/
public static int[] bubbleSort(int[] arr){
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr.length-i-1; j++) {
if(arr[j] > arr[j+1]){
arr[j+1] = arr[j+1]^arr[j];
arr[j] = arr[j+1]^arr[j];
arr[j+1] = arr[j+1]^arr[j];
}
}
}
return arr;
}
2.选择排序
/**
* 选择排序
* 选择排序就是从第一趟开始,用第一个元素和剩下中的每一个元素比较,
*
* ,就和第一个元素交换值,最后使得第一个元素中的值最小,
* 第二趟选择出第二小的放到第二元素,依次,使得数组有序。
*/
public static int[] SelectionSort(int[] arr){
for (int i = 0; i < arr.length-1; i++) {
for (int j = i +1; j <arr.length-1; j++) {
if(arr[j] > arr[i]){
arr[i] = arr[i]^arr[j];
arr[j] = arr[i]^arr[j];
arr[i] = arr[i]^arr[j];
}
}
}
return arr;
}
3.插入排序
/**
* 插入排序
* 插入排序类似于打扑克牌,从第二张牌开始插入,小的插到大的前面,然后使其有序。
* 再拿第三张牌来,找到合适的位置继续插入,使这三张有序。在第四张直至全部插入有序。
*/
public static int[] insertSort(int[] arr){
for (int i = 1; i < arr.length; i++) {
int value = arr[i];
for (int j = i -1;j>=0;j--) {
if(arr[j] > value){
arr[j+1] = arr[j];
}else{
arr[j+1] = value;
break;
}
}
}
return arr;
}
22 CPU占用过高,定位方法
用top命令定位那个进程对cpu占用过高
ps H -eo pid,tid,%cpu |grep 进程id (定位那个进程)
jstack 进程id
可以根据线程id,找到有问题的线程,并找到代码
23 线程运行长时间没有结果
猜测是发生了死锁,排查方式同22
24堆
通过new关键字创建的对象都会使用堆内存
堆是线程共享的,所以堆中的对象都要考虑线程安全的问题
堆中有垃圾回收机制
jmap -head 命令用来查看堆内存的占用
25 设置JVM内存的参数有四个
-Xmx Java Heap最大值,默认值为物理内存的1/4,最佳设值应该视物理内存大小及计算机内其他内存开销而定;
用来设置你的应用程序能够使用的最大内存数(看好,致使你的应用程序,不是整个jvm),如果你的程序要花很大 内存的话,那就需要修改缺省的设置,
-Xms Java Heap初始值,Server端JVM最好将-Xms和-Xmx设为相同值,开发测试机JVM可以保留默认值;
用它来设置程序初始化的时候内存栈的大小,增加这个值的话你的程序的启动性能会得到提高。不过同样有前面的限制,以及受到xmx的限制。
-Xmn Java Heap Young区大小,不熟悉最好保留默认值;
-Xss 每个线程的Stack大小,不熟悉最好保留默认值;
-XX:PermSize 永久区的大小。
-XX:+UseParNewGC 使用并行收集算法。
26 堆内存诊断
jps工具:查看当前系统中有哪些java进程
jmap工具:查看堆内存占用情况(jmap -head 进程id)
jconsole:图形界面的,多功能检测工具,可以连续检测
jvisualvm:图形界面,多功能检测工具,可以连续检测,可以抓取快照,进行详细分析
26 redis
redis默认有16个数据库,默认使用第0个
redis 是基于内存操作的,是单线程的
redis 的瓶颈是基于机器的内存和网络带宽
redis 是C语言写的 读11w/s,写8.1w/s
27 redis基础命令
key * #查看所有key
EXISTS name # 查看当前的key是否存在
move name 1 #移除当前的key
EXPIRE name 10 #设置key的过期时间,单位秒
ttl name #查看当前key的剩余过期时间
get name #获得key的值
type name #查看当前key的值得类型
flushdb #清空当前数据库
flushall #清空所有数据库
可以使用‘select 数据库编号’切换数据库
DBSIZE查看数据大小
set key value #给key设置值为value
STRLEN key #获取字符串key的长度
incr key #给key自增
decr key #给key自减
INCRBY key 10 #给key加10
DECRBY key 10 #给key减10
28 redis为什么单线程还那么快?
redis是将所有数据存放在内存中的,所以使用单线程操作效率比是最高的,因为多线程中CPU是上下文会切换,所以对于内存系统来说,如果没有上下文切换效率就是最高的。
29 redis类型
String
字符串追加命令:APPEND
字符串截取命令:
List
Set
Hash
ZSet
29 redis持久化
RDB(Redis DataBase)
在指定的时间间隔将内存中的数据集快照写入磁盘,记快照文件,保存的文件是dump.rdb
快照触发机制:满足配置文件中的save规则
执行flushall命令
退出redis
快照恢复方式:只需要将rdb文件放到redis启动目录,redis启动就会自动检查dum.rdb
优点: 适合大规模的数据恢复
对数据的完整性要求不高
缺点: 需要一定的时间间隔操作,如果redis意外宕机,最后一次的操作数据就没有了
fok进程的时候回会占用进程,占用一定的内存空间
AOF(Append Only File)
将我们的所有命令都记录下来,恢复的时候就把这个文件全部执行一遍;、
以日志的形式来记录每个写操作,将redis执行过的所有写操作指令都记录下来,只许追加文件,不可以修改文件,redis启动时会读取该文件进行重构数据库,即启动时根据日志文件将写操作从前到后全部执行一次以完成数据库的恢复工作。
aof保存的文件是appendonly.aof.
默认是不开启的,需要手动配置
如果aof操作日志文件出现错误,redis是启动不了的,我们需要修复aof文件,redis提供了redis-check-aof 工具来修复aof文件
优点: 每一次修改都同步,数据完整性更强
每秒同步一次,可能会丢失一秒的数据
从不同步,效率最高
缺点: 相对于数据文件来说,aof远远大于rdb,修复速度比rdb慢
aof效率比rdb低
30 redis主从复制
主从复制,读写分离,主机负责写,从机负责读;数据从主机复制到从机,单项复制;减轻服务器压力,redis集群最少三台;
主从复制的作用主要包括:
数据冗余
故障恢复
负载均衡
高可用集群
只要在公司中,主从复制必须是集群架构。
主从复制原理:
从机启动成功连接到主机后悔发送一个同步命令,进行一些全量复制,之后就会增量复制完成同步。
只要重新连接主机,就会有一次全量复制自动执行。
31 springboot核心注解
@SpringBootApplication:标注这个类是一个springboot应用
@SpringBootConfiguration:springboot的配置
@Configuration:spring的配置类
@Component:说明这也是一个spring组件
@EnableAutoConfiguration:自动配置
@AutoConfigurationPackage:自动配置包
@Import({Registrar.class}):自动配置,包注册
@Import({AutoConfigurationImportSelector.class}):自动配置导入选择
@ConditionalOn**XXX**:判断条件是否达到,才去加载该对象
32 springboot自动配置核心文件
springboot所有自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这个文件,但不一定都生效,要判断条件是否成立。只要导入了对应的start,都有对应的启动器,有了启动器,自动装配就会生效,然后配置成功,不再需要我们去编写配置文件。
这也是springboot对于spring来说的一大优点,即自动装配、简化开发。
33 springboot启动类
33 ThreadLocal
ThreadLocal 是java中提供的本地存储机制,可以利用该机制将数据缓存在某个线程内部,该线程可以在任意时刻,任意方法中获取缓存的数据
ThreadLocal底层是通过ThreadLocalMap来实现的,每个Thread对象中都存在一个ThreadLocalMap,Map的key为ThreadLocal对象,value是需要缓存的值