Java部分:
- String、StringBuilder、StringBuffer的区别及优劣:
String:底层用char[]数组实现,并且数组内容不可改变(即用final修饰),因此不同的字符串即为不同的对象
如:String s = "1";s += 2;(此时s="12"),此时已经有两个字符串对象"1"、"12"
StringBuilder:非线程安全,底层用char[]数组实现(继承自AbstractStringBuilder),但可修改数组内容(未用final修饰),因此可以改变字符串内容(而不另外生成字符串对象)
当要追加的内容超过数组剩余空间时,需扩容数组,由于数组需要连续的地址空间,此处需整个复制原有数组内容,会消耗较多的时间和内存,因此使用的时候尽量预估一下会有多少字符,设置初始化char[]数组大小,避免过多扩容
StringBuffer:线程安全,底层用char[]数组实现(同StringBuilder一样继承自AbstractStringBuilder),同StringBuilder的区别,StringBuffer的方法是线程安全的,因此效率不如StringBuilder。
2.ArrayList和LinkedList的区别及优劣:
ArrayList:底层用Object[]数组实现,因此可实现随机访问(根据数组下标)访问速度较快,但是同StringBuilder类似,当数组长度不够时需扩容时或者删掉数组中某一元素时,需复制原有数组内容,比较消耗时间和内存,增删较慢
LinkedList:底层用双向链表实现,仅提供链表的头指针和尾指针,因此不可随机访问,但是增删时只需将需删除元素从链表中摘除,因此增删较快
注:具体实现可参考源码
3.什么时候需要用到迭代器?
容器类中都提供了迭代器,可通过迭代器访问容器中元素,当遍历集合中元素时,需改变集合中元素的个数(即增删集合中元素),可能会报错,此时需用到迭代器
而用迭代器,则可正常操作:
注:有一种设计模式叫迭代器模式,有兴趣的可以自己了解一下
4.java中有几种产生线程的方式?
继承Thread类:由于java的单继承机制,继承了Thread类之后不可再继承其他类,因此不建议用这种方式实现多线程,建议用第二种方式
实现Runnable接口:实现Runnable接口中的run()方法
线程池:可从已有的线程池中获取线程(第三种我没有答上来,因为个人感觉问的是如何产生线程,利用线程池是获取已有的线程)(线程池的好处,减少了产生线程的开销,可统一管理线程)
注:启动新线程的时候,应调用新线程的start()方法而非run()方法,具体如下例所示:
5.如何获取线程的终止状态(不是如何终止线程或者判断线程的状态)?
这个目前还没有想明白,后续有结果了会更新,知道的大神请指点。
6.java中如何加载类?
当时面试的时候只讲了两种,一种是用classLoader.loadClass(),另一种是Class.forName("class name"),具体例子见下图
重新查了一下资料,整理一下java虚拟机何时会加载类:
1.创建类的实例
2.访问类或者接口的静态成员变量
3.调用类的静态方法
4.反射(Class.forName("xxx.xxx.xxx"))
5.初始化一个类的子类(相当于对父类的主动使用),不过直接通过子类引用父类元素,不会引起子类的初始化
6.java虚拟机被标明为启动类的类(含有main方法的)
(参考文章:https://www.cnblogs.com/zhguang/p/3154584.html)
7.java垃圾回收机制,手动调用垃圾回收的时候,是否会立即回收?
在网上查的结果是并不会立即回收,具体回收时机参考文章:https://blog.csdn.net/yewei02538/article/details/52386642/
但是刚刚我看了源码,当调用System.gc()时,是会立即回收的,并不像上面文章讲的那样会先调用Runtime.getRuntime().runFinalization()
如下图:
可能是不同的jdk版本的不同处理策略,我看的版本是jdk1.8(换了一下1.7版本的,还是会直接调用Runtime.getRuntime().gc();)
8.见过或者用过哪些常用的设计模式?
设计模式有很多,几句话讲不完,可参考这个文章:https://blog.csdn.net/dean_hu/article/details/71195133
9.负载均衡策略?
这里简要列一下:http重定向、DNS负载均衡(将DNS服务器当作负载均衡服务器)、反向代理负载均衡(转发http请求)、IP负载均衡(LVS-NAT)、直接路由(LVS-DR数据链路层)、IP隧道(LVS-TUN)。
其实我也只是知道个大概,具体细节还有很多需要深究,详细一点的参考这篇文章:https://blog.csdn.net/wt725/article/details/58580315
10.HashMap和HashTable一个是线程不安全的(HashMap,速度较快),一个是线程安全的(HashTable,速度较慢),如何实现在线程安全的情况下,提交效率?
大致思路:将锁的粒度细化。访问元素的时候,判断元素会落到哪个位置,若之前是锁住整个table,仅锁住该位置为头结点的链表,其余位置的元素则可以正常操作。
数据库部分
1.mysql数据库加锁语句
Locking read(SELECT ... FOR UPDATE(排他锁) OR SELECT ... LOCK IN SHARE MODE(共享锁))
UPDATE以及DELETE语句通常会在他 扫描的索引所有范围上加锁,忽略没有用到索引的那部分where语句
举个栗子:
CREATE TABLE `test` (
`id` int(11) NOT NULL DEFAULT '0',
`name` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
select * from test where id > 3 and name <'A' for update;
这条SQL语句的会将所有id>3的记录进行加锁,而不是id>3 and name <'A' 进行加锁,因为name上面没有索引
详细可参考文章:http://www.fordba.com/locks-set-by-different-sql-statements-in-innodb.html
2.redis有哪些数据结构?
redis可以存储键和五种不同类型的值之间的映射:
- String字符串
- List列表
- Set集合
- Hash散列
- Zset有序集合
详细可参考文章:https://blog.csdn.net/fan510988896/article/details/71730696
3.mysql数据库建表时使用过哪些存储引擎(如事务型或非事务型,innoDB等)?
MySQL存储引擎在另外一篇博客中介绍:https://blog.csdn.net/weixin_38823568/article/details/81702397
其他部分
1.对http协议的了解,http三次握手
Http使用的TCP协议,实际是TCP的三次握手:
- 客户端发送请求到服务端请求建立连接(SYN包)
- 服务端收到请求后,发送自己的连接请求(SYN)以及对收到的客户端请求包的确认(ACK),即SYN+ACK包
- 客户端收到服务端的SYN+ACK包,向服务器发送ACK确认
以及四次断开连接过程,具体可见下图:
图片来源及参考文章:https://blog.csdn.net/yanxinrui0027/article/details/70243665
2.对https的了解?
个人对Https并没有太多了解,上网查了一下,感觉这篇文章写的挺通俗易懂的:https://www.cnblogs.com/xinzhao/p/4949344.html,后续应该会更详细的研究一下。