归纳知识总结与面试题型(2020-11-22起 持续更新)
1.Java
一、Java 基础
1. jre与jdk的区别
- jre:Java Runtime Environment 的简称,是运行环境,安装jre会自带JVM虚拟机,java源码需要使用虚拟机才能运行在windows或者Linux系统上运行
- jdk:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境 下载jdk时也包含jre。
- 分析:具体来说需要运行java代码jre就行了,而需要开发编写java程序,只需jdk就够了
2.equals与==的区别
Student s=new Student("a", 18);
Student s1=new Student("a", 18);
System.out.println(System.identityHashCode(s)); //打印内存地址2018699554
System.out.println(System.identityHashCode(s1));//打印内存地址1311053135
System.out.println(s==s1);//false
---------------------------------------------------------------------
//每个类的内存地址都是随机变化的 但每个对象的内存地址不可能一样
//如果要判断对象是否一样就需要在Student类里重写equals方法了
//我们使用的是开发工具的快捷生成 方法体重还是使用==判断值的
public class Student {
private String name;
private int num;
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (num != other.num)
return false;
return true;
}
}
- == 解读:基本类型:比较的是值是否相同;引用类型:比较的是引用是否相同;
- equals:是Object类下的方法,在object类里比较的是内存地址,是==,而String类里重写了equal方法,里面比较的是值的内容,如果需要比较对象里的值时,需要重写equals方法
- 总结== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
3. 两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
1 答案是不对,两个对象的 hashCode()相同,equals()不一定 true。
因为我们可以重写ehashCode的规则使其内存地址样,也可以重写equals,改变 比较的方法,因为在散列表中,hashCode()相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。
4. final 在 java 中有什么作用?
- 被final修饰的类 不能被其他类继承
- 被final修饰的变量只能赋值初始值一次,如果没有赋值初识值,编译器则报错;
- 被final修饰的方法不能被子类重写
- 总结:final是常量的意思,被修饰是变量、方法、类是不能被修改的;
5. java 中的 Math.round(-1.5) 等于多少?
等于 -1,因为在数轴上取值时,中间值(0.5)向右取整,所以正 0.5 是往上取整,负 0.5 是直接舍弃。
6. String 属于基础的数据类型吗?
String不是基本数据类型,基本数据类型有:byte int short lang double float boolean char 属于java中的基本数据类型,String是不可变的引用数据类型.
注意:String是java.lang包下的一个类,底层是Cahr[] value数组是被final修饰的
7. java 中操作字符串都有哪些类?它们之间有什么区别?
- java中操作字符串的类有String,StringBuffer,StringBuilder三大类
- String与StringBuffer,StringBuilder的区别:首先String是不可变字符串 底层是一个被final修饰的Object数组,所以是不可变的,每次创建一个String对象会在常量池创建出来,然后将指针重新指向他,如:“a”+“ab”=“aab”,字符串常量池会创建这三个不一样的对象.
- StringBuffer与StringBuilder是可变字符串,在抽象类 AbstractStringBuilder底层也是char[] value,但没有被final修饰
//通过反射拿到抽象类char数组的源码
StringBuffer buff=new StringBuffer("123");
Class c=buff.getClass();
Class superC= c.getSuperclass();
Field f= superC.getDeclaredField("value");
f.setAccessible(true);
char[] vlaue=(char[]) f.get(buff);
System.out.println(vlaue);//123[][][][][][][][][]... 这里是初识容量16;
- StringBuffer与StringBuilder的区别:1.他们都是可变字符串,StringBuffer底层的方法大部分是用synchronize关键字修饰的,是线程安全的,StringBuilder是非线程安全的 2.StringBuffer的toString是带缓冲的,而StringBuilder的toString是直接取对象.
- 总结:String:适用于少量的字符串操作的情况,StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况,StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
8. String str="i"与 String str=new String(“i”)一样吗?
内存地址的分配会不一样
如图:
解析:
String str=“i”;str是直接指向常量池 而String str=new String(“i”);
str是先指向堆内存,str先保存的是堆内存的地址,然后推里在指向常量池;
9. 如何将字符串反转?
使用StringBuffer和StringBuilder的reverse()方法.注:String没有reverse()方法
StringBuffer t=new StringBuffer("123456789");
t=t. reverse() ;
System.out.println(t);//987654321
10.String 类的常用方法都有那些?
- equals()比较String的值
- indexOf()传入字符串,找到该字符串返回该字符所在位置,未找到返回-1
- charAt():返回指定索引处的字符。
- replace():字符串替换。
- trim():去除字符串两端空白。
- split():分割字符串,返回一个分割后的字符串数组。
- getBytes():返回字符串的 byte 类型数组。
- length():返回字符串长度。
- toLowerCase():将字符串转成小写字母。
- toUpperCase():将字符串转成大写字符。
- substring():截取字符串。
11.String,StringBuffer,StringBuilder在经过方法时会改变自身吗?
String调用方法时不会改变自身,StringBuffer与Stringbuilder调用append时会改变自身
12. 抽象类必须要有抽象方法吗?
抽象类里不一定有抽象方法,但有抽象方法的类,一定是抽象类或接口
13.普通类和抽象类有哪些区别?
1.普通类里不能有抽象方法而抽象类可以有
2.抽象可不能实例化(不能直接实例化,直接实例化需要重写抽象方法),而实例类可以实例化
14.抽象类能使用 final 修饰吗?
抽象类是不能被final修饰的,抽象类其实就是让其子类继承的,被final修饰后就抽象类就没有任何意义了!
而且编译器这时也会报错!
15. 接口和抽象类有什么区别?
- 构造方法:抽象类可以有构造方法供子类使用,接口中不能有构造方法
- 抽象方法:抽象类可以有抽象方法也可以有成员方法,接口只能有抽象方法JDK8新增default修饰的默认方法可以写方法体,还有static修饰的也有方法体,JDK9新增private修饰的私有方法可以写方法体,供接口本类使用
- 声明方式:抽象类使用abstract声明,接口使用interface声明
- 实现数量:继承抽象类的类只能单继承使用extends,而实现接口的类可以多实现使用implement(为弥补单继承减少程序的灵活性)
- main方法:抽象类可以有main方法,接口不能有main方法
16. java 中 IO 流分为几种?
线上IO流继承关系图 在java.IO包下
根据数据的流向分为:输入流和输出流。
- 输入流 :把数据从
其他设备
上读取到内存
中的流。 - 输出流 :把数据从
内存
中写出到其他设备
上的流。
格局数据的类型分为:字节流和字符流。
- 字节流 :以字节为单位,读写数据的流。(byte)
- 字符流 :以字符为单位,读写数据的流。(char)
流分为:文件流,缓冲流,转换流,打印流,对象流,File 类
二、集合
17. java 容器都有哪些?
直接上集合继承图
Java容器的集合有:
- List接口下的ArrayList,LinkedList,Vector
- set接口下的HashSet,TreeSet
- map接口下的HashMap,TreeMap,Properties
18. Collection 和 Collections 有什么区别?
Collection接口在java.util报下,是单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是java.util.List
和java.util.Set
。其中,List
的特点是元素有序、元素可重复。Set
的特点是元素无序,而且不可重复。List
接口的主要实现类
Collections是java.util包下的,他是集合的工具类,常用的方法有:
- boolean addAll(Collection c, T… elements)一次性添加多个元素
- void shuffle(List<?> list)打乱集合顺序。
- void sort(List list)`:将集合中元素按照默认规则排序。
- …
19. List、Set、Map 之间的区别是什么?
-
List
1. 可以允许重复的对象。
2. 可以插入多个null元素。
3. 是一个有序容器,保持了每个元素的插入顺序,输出的顺序就是插入的顺序。
4. 常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,它提供了使用索引的随意访问,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。 -
Set:
1. 不允许重复对象
2. 无序容器,你无法保证每个元素的存储顺序,TreeSet通过 Comparator 或者 Comparable 维护了一个排序顺序。
3. 只允许一个 null 元素
4. Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序容器。 -
Map:
1. Map不是collection的子接口或者实现类。Map是一个接口。
2. Map 的 每个 Entry 都持有两个对象,也就是一个键一个值,Map 可能会持有相同的值对象但键对象必须是唯一的。
3. TreeMap 也通过 Comparator 或者 Comparable 维护了一个排序顺序。
4. Map 里你可以拥有随意个 null 值但最多只能有一个 null 键。
5. Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)
20. 说一下 HashMap 的实现原理?
在JDK1.8之前,HashMap是用哈希表底层采用数组+链表实现 即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
简述上图操作:当我使用HashMap的put存入key value值时,首先判断该集合大小是否需要扩容,在将该值的key值通过Object类的hashCode()方法得到hash值,然后判断数组是否有值,如果没有元素直接插入,如果有元素进行equals判断hash值,若找到该hash值,就放入该数组进入链表结构,如果链表结构没有元素直接插入,如果有元素进行equals判断key的值,如果key值重复就覆盖value值,没有该key值就添加入链表末尾,若链表长度大于8就转换为红黑树结构,当小于6时在次转换为链表结构
21. 说一下 HashSet 的实现原理?
HashSet底层调用了HashMap,实际上是存入到了hashMap的key部分.
查看HashSet源码,其操作底层都是通过调用HashMap方法实现的,HashSet会将元素存储在HashMap的key集合中,然后为value赋一个static空对象PRESENT。
22. ArrayList 和 LinkedList 的区别是什么?
- ArrayList:
- 数据结构:采用数组
- 查询快增删改慢
- LinkedList:
- 数据结构:双向链表
- 查询慢,增删改快
备注:只是数据结构不同
23. (了解)hash冲突是什么?它的解决方法有几种?
博主之前看面试视频时,偶尔看过这类面试官提问?现在给大家介绍下
在同一个hash数组的链表里,你们都以为hash值是一样的对吧?但同一个链表里的hash值可能不一样,也有可能一样,这是因为通过hash算法%(取模)得到的,不一定所有的hash值都是唯一的。但最后转换的数组下标一定是相同的。
结论:hash值相同时是一定在同一个链表上,但由于hash算法转换后的数组下标有可能相同,此时发生了hash碰撞.
解决方案: 1.开放定址法(线性探测再散列,二次探测再散列,伪随机探测再散列) 2.再哈希法(重新计算直到不发生冲突) 3.链地址法(Java hashmap就是这么做的) 4.建立一个公共溢出区(就是把冲突的都放在另一个地方,不在表里面)
24. 如何实现数组和 List之间的转换?
- List转换成为数组:调用ArrayList的toArray方法。
- 数组转换成为List:调用Arrays的asList方法。
25. Array 和 ArrayList 有何区别?
- Array:数组的大小是固定的,只能存储基本数据类型与引用数据类型.
- ArrayList:list集合的大小是可以指定的,当容量满时,会自动扩容1.5倍,只能存储引用数据类型,功能比 Array更丰富;如(contain(),remove()…)
26. ArrayList怎么转换转换线程安全的?
-
使用Vector代替,底层的大部分方法都是使用synchronize修饰
-
使用CopyOnWriteArrayList,读写分离,写入时复制
解析:CopyOnWriteArrayList是Java并发包中提供的一个并发容器,它是个线程安全且读操作无锁的ArrayList,写操作则通过创建底层数组的新副本来实现,是一种读写分离的并发策略。使用这种策略的还有CopyOnWriteSet,另外还有mysql的MVVC也是使用的这种原理 -
Collections.synchronizedList(new ArrayList<>()) 通过调用该方法将ArrayLsit中的方法加上synchronize关键字
分析:以上解决方法推荐第二种或者第三种
27. 迭代器 Iterator 是什么?
迭代器是一种术语:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
28. 迭代器 Iterator 与增强循环 foreach
我们知道iterator与foreach都能遍历数组与集合但他们的变量方式的效率上的各有有事,foreach的底层使用了iterator
从数据结构角度分析,for循环适合访问顺序结构,可以根据下标快速获取指定元素.而Iterator 适合访问链式结构,因为迭代器是通过next()和Pre()来定位的.可以访问没有顺序的集合.
而使用 Iterator 的好处在于可以使用相同方式去遍历集合中元素,而不用考虑集合类的内部实现(只要它实现了 java.lang.Iterable 接口),如果使用 Iterator 来遍历集合中元素,一旦不再使用 List 转而使用 Set 来组织数据,那遍历元素的代码不用做任何修改,如果使用 for 来遍历,那所有遍历此集合的算法都得做相应调整,因为List有序,Set无序,结构不同,他们的访问算法也不一样.
三、多线程
29. 并行、并发、串行有什么区别?
先上图:
- 串行:有n个任务,由一个线程按顺序排队执行。由于任务、方法都在一个线程执行所以不存在线程不安全情况,也就不存在临界区的问题。
- 并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。
- 并行:单位时间内,多个处理器或多核处理器同时处理多个任务,是真正意义上的“同时进行”。
2.Mybatis,Spring,SpringMVC三大框架
一、Mybatis
30. #与$的区别?
1. #使用 ?在sql语句中做站位的, 使用PreparedStatement执行sql,效率高
2. #能够避免sql注入,更安全。
3. $不使用占位符,是字符串连接方式,使用Statement对象执行sql,效率低
4. $有sql注入的风险,缺乏安全性。
5. $:可以替换表名或者列名
二 、Spring
31. @AutoWired与@Rrsouce的区别?
- @AutoWired 是spring包下的,默认按照类型自动注入,若需要使用名称自动注入 需要使用@Qualifier(" 变量名称")的方式
- @Rrsouce 是jdk包下的,默认使用类名自动注入,若类名未找到,则使用类型注入