20200713 by 1z
- 请解释一下为什么String不可变?
1.String不可变的成因
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
@Stable
private final byte[] value;
//...
}
由于在String,类自身被final修饰,而且内部的字节数组 byte[] value 同样被final修饰,因此在不可变
2.从应用角度谈谈为什么String不可变
* 当字符串不可变的时候,字符串池才有可能实现,不同的字符串变量会指向同一个字符串池中的字符串,如果字符串是可变的会引起很严重的安全性问题
* socket编程中主机名和端口都是以字符串形式传入,因为不可变,所以保证了安全
* 字符串是不可变的,所以在它创建的时候hashcode已经被缓存了,不变性保证了hash码的唯一性,不需要重新进行计算。使得字符串适合作为Map的键(安全 and 快速 )
-
请讲讲java有哪些特性,并举一个和多态有关的例子?
封装 继承 多态 多态的例子: class : Animal class : Cat Dog extends Animal Cat void bark(); // 猫叫 Dog void bark(); // 狗叫 Animal animal = new Dog(); Animap animal1 = new Cat(); animal.bark(); animal1.bark(); 编译期都是 Animal 运行期体现出多态性
-
请说明一个wait方法的底层原理?
链接:https://www.nowcoder.com/questionTerminal/34f9ba9283f54975939bc631eead1e64
来源:牛客网
wait方法将当前线程放入wait set,等待被唤醒,并放弃lock对象上的所有同步声明。
1、将当前线程封装成ObjectWaiter对象node;
2、通过ObjectMonitor::AddWaiter方法将node添加到_WaitSet列表中;
3、通过ObjectMonitor::exit方法释放当前的ObjectMonitor对象,这样其它竞争线程就可以获取该ObjectMonitor对象。
4、最终底层的park方***挂起线程;
(最后与之对应的notify方法)会随机唤醒_WaitSet中随机一个线程
- 请说明List,Set,Map三个接口获取元素的时候,各有什么特点?
List 和 Set都是单列元素的集合。它们有一个共同的父节点 Collection
1.List是一个维护着先后顺序的集合
* 存元素: 采用add(Object)进行存储,每次加入的对象按照先后顺序进入,也可以进行插队,即调用add(int index,Object)方法
* 取元素
1. Iterator 接口取得所有的数据,然后进行遍历
2. 采用 get(int index)进行遍历
List<Integer> list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
for (Integer iVal : list) {
System.out.println(iVal);
}
2.Set是一个内部存储顺序随机的集合,不允许有重复的key存在,只能存在一个null key
* 存元素: 调用了add方法,add方法有一个boolean的返回值,当集合中没有某个元素,此时add方法可成功加入该元素时,则返回true;当集合含有与某个元素equals相等的元素时,此时add方法无法加入该元素,返回结果为false。
* 取元素: 以iterator的方式 随机取出
Set<Integer> set = new HashSet();
set.add(1);
set.add(2);
set.add(3);
for (Integer iVal : set) {
System.out.println(iVal);
}
3.map是一个单列的集合
* 存数据 put(obj key,obj value),每次存储时,要存储一对key/value,不能存储重复的key,这个重复的规则也是按equals比较相等。
* 取数据
1. 用get(Object key)方法根据key获得相应的value
2. 获取所有的key的集合(keyset) 获取value
3. 获取key value得集合 keyEntry
- 阐述ArrayList,Vector,LinkedList的存储性能和特性?
ArrayList使用数组去存储数据。ArrayList在加入数据的使用,默认声明一个长度为10的数组(Object[]elementData),然后进行动态扩容操作(* 1.5),因为底层是数组,所以查找快但是增减慢
vector作为遗留的数据结构,底层实现和ArrayList差不多,默认声明一个长度为10的数组(Object[]elementData),然后进行动态扩容操作(* 2)
LinkedList
LinkedList使用双向链表实现存储(将内存中零散的内存单元通过附加的引用关联起来,形成一个可以按序号索引的线性结构,这种链式存储方式与数组的连续存储方式相比,内存的利用率更高),按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。(但是增减的效率更慢)
- 请判断List,Set,Map是否继承自Collection接口?
List,Set继承自Collection
Map 不继承Collection
- 请你讲讲你锁知道的常见集合类和主要方法?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sX8KWMtz-1594622809944)(C:\Users\Lzinner\AppData\Roaming\Typora\typora-user-images\1594620841151.png)]
参考链接: https://blog.csdn.net/qq_30711091/article/details/88847892
- 请说明Collection 和 Collections的区别?
java.util.Collection是集合类的上层接口,里面包含了一些集合的基础操作
Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
常见方法:
Collections
是一个集合框架的帮助类,里面有一些对集合的排序,搜索等操作,服务于java.util.Collection
参考链接: https://www.cnblogs.com/fysola/p/6021134.html
- 简要说明ArrayList,Vector,LinkedList的存储性能是什么?
1. ArrayList使用数组去存储数据。ArrayList在加入数据的使用,默认声明一个长度为10的数组(Object[]elementData),然后进行动态扩容操作(* 1.5),因为底层是数组,所以查找快但是增减慢
2. vector作为遗留的数据结构,底层实现和ArrayList差不多,默认声明一个长度为10的数组(Object[]elementData),然后进行动态扩容操作(* 2)
3. LinkedList
LinkedList使用双向链表实现存储(将内存中零散的内存单元通过附加的引用关联起来,形成一个可以按序号索引的线性结构,这种链式存储方式与数组的连续存储方式相比,内存的利用率更高),按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。(但是增减的效率更慢)
- 请说明ArrayList 和 LinkedList的区别?
1. 底层实现
ArrayList的底层是数组,LinkedList的底层是双向链表
2.效率
ArrayList的查询效率较高 LinkedList的增减效率更高
3. 组成部分
ArrayList由object[]的节点组成
LinkedList由节点信息(元素内容) 和 前驱 后驱指针组成
参考链接: https://www.cnblogs.com/lingshang/p/10897912.html