众安保险笔试
1.String 与StringBuilder StringBuffer的区别?
- String:字符串常量
- StringBuffer:字符创变量
- StringBuilder:字符创变量
- StringBuilder:线程非安全的
- StringBuffer:线程安全的
- 三者在执行速度方面的比较:StringBuilder > StringBuffer > String
2.静态代码块 构造代码块 构造方法的执行顺序及注意问题?
- 静态代码块->构造代码块->构造方法
public class Test {
private int number=0;
//静态代码块
static{
System.out.println("静态代码块执行!");
}
//构造代码块
{
System.out.println("构造代码块执行!");
number=1;
}
//构造方法
public Test(){
System.out.println("构造方法执行!");
System.out.println(number);
}
public static void main(String[] args) {
new Test();
}
}
3.Activity的几种启动模式,各自举例说明?
- standard 标准的启动模式 -mainfest中没有配置就默认标准模式
- singleTop 单一栈顶模式 - 登录页面
- singleTask 单一任务栈模式 - Home 主页面
- singleInstance 单一实例模式 - 小程序 系统Launcher、锁屏键、来电显示等系统应用
4.RecyclerView 几种LayoutManager?
- LinearLayoutManager 线性布局管理器
- GridLayoutManager 网格布局管理器
- StaggeredGridLayoutManager 交错网格布局管理器
5.java中 int 占用几个字节?
类型 | 字节数 | 最小值 | 最大值 |
---|---|---|---|
boolean | 未指定,至少1字节,仅定义为取字面值true或false | - | - |
byte | 1 | -128(-2^7) | 127(2^7-1) |
short | 2 | -32768(-2^15) | 32767(2^15 - 1) |
char | 2 | \u0000(即0) | \uffff(即65,535) |
int | 4 | -2,147,483,648(-2^31) | 2,147,483,647(2^31 - 1) |
long | 8 | -9,223,372,036,854,775,808(-2^63) | 9,223,372,036,854,775,807(2^63 -1) |
float | 4 | (指数8位,尾数23位,指数偏移量127) | 3.4028235E38 1.4E - 45 |
double | 8 | (指数11位,尾数52位,指数偏移量1023) | 1.7976931348623157E308 4.9E - 324 |
6.Activity 冷启动、热启动的时间?
冷启动:
在启动应用时,系统中没有该应用的进程,这时系统会创建一个新的进程分配给该应用;热启动:
在启动应用时,系统中已有该应用的进程(例:按back键、home键,应用虽然会退出,但是该应用的进程还是保留在后台);-
使用命令行:adb shell am start -W com.ubtechinc.cruzr.voicedemo/.home.MainActivity 查看时间
Status: ok Activity: packageName/activityName ThisTime: 1298 TotalTime: 1298 WaitTime: 1308 Complete
7.画出Handler原理图?
Handler原理
8.算法题 快排 双向链表(二选一)?
-
快速排序
public static int[] quickSort(int[] array,int start,int end) { if (start<=end) { int m = start; int n = end; int the_base = the_array[m]; while (m
=the_base)) { n--; } array[m]=array[n]; while((m 双向链表
public class DoubleLink {
private class Node {
/**
* 节点值
*/
private T vlaue;
/**
* 前一个节点
*/
private Node prev;
/**
* 后一个节点
*/
private Node prex;
public Node(T value,Node prev,Node prex){
this.vlaue = value;
this.prev = prev;
this.prex = prex;
}
}
/**
* 链表长度
*/
private int size ;
/**
* 头节点
*/
private Node head;
public DoubleLink(){
/**
* 头结点不存储值 并且头结点初始化时 就一个头结点。
* 所以头结点的前后节点都是自己
* 并且这个链表的长度为0;
*/
head = new Node<>(null, null, null);
head.prev = head.prex ;
head = head.prex;
size = 0;
}
public int getSize(){
return this.size;
}
/**
* 判断链表的长度是否为空
*/
public boolean isEmplty(){
return size == 0;
}
/**
* 判断索引是否超出范围
*/
public void checkIndex(int index){
if(index<0||index>=size){
throw new IndexOutOfBoundsException();
}
return;
}
/**
* 通过索引获取链表当中的节点
*
*/
public Node getNode(int index){
/**
* 检查该索引是否超出范围
*/
checkIndex(index);
/**
* 当索引的值小于该链表长度的一半时,那么从链表的头结点开始向后找是最快的
*/
if(index cur = head.prex;
for(int i=0;i cur = head.prev;
int newIndex = size - (index+1);
for(int i=0;i cur){
return cur.vlaue;
}
/**
* 获取第一个节点的值
*/
public T getFirst(){
return getValue(getNode(0));
}
/**
* 获取最后一个节点的值
*/
public T getLast(){
return getValue(getNode(size-1));
}
/**
* 插入节点
*/
public void inesert(int index,T value){
//如果这次插入时 链表是空的
if(index==0){
//这个节点的
Node cur = new Node(value, head, head.prex);
head.prex.prev = cur;
head.prex = cur;
size++;
return;
}
/**
* 先根据给出的插入位置 找到该链表原来在此位置的节点
*/
Node node = getNode(index);
/**
*放置的位置的前一个节点就是原节点的前置节点 而后节点就是原节点
*/
Node cur = new Node(value,node.prev,node);
/**
* 现将该位置也就是 原节点的前节点的后节点 赋值成为新节点
* 然后将新节点的后置节点的值赋值成为原节点
*/
node.prev.prex = cur;
node.prev = cur;
size++;
}
/**
* 向表头插入数据
*/
public void insertTo(T Value)
{
inesert(0,Value);
}
/**
* 将元素插入到链表的尾部
*/
public void insertTotatil(T vlaue){
Node cur = new Node<>(vlaue,head.prev, head);
//head.prev 代表原来的尾部节点
//遵循两个原则 一 新插入节点的前一个节点的后一个节点为新节点。新节点的后一个节点的前一个节点是新节点
head.prev.prex = cur;
head.prev = cur;
size++;
}
/**
* 删除节点的方法
*/
public void del(int index){
checkIndex(index);
Node cur = getNode(index);
//记住此时的指针还没断开 赋值以后才相当于断开
cur.prev.prex = cur.prex;
cur.prex.prev = cur.prev;
size--;
cur = null;
return;
}
/**
* 删除第一个节点
*/
public void delFirst(){
del(0);
}
/**
* 删除最后一个节点
*/
public void delLast(){
del(size-1);
}
}
- 十大经典排序算法最强总结(含JAVA代码实现)
技术面 第一轮
1.首先介绍一下自己
2.讲一讲你做的项目的核心贡献
3.HashMap的源码分析?
- HashMap实现原理
4.HashTable的实现原理
-
重点讲一个Hashmap与HashTable的区别
- Hashtable不允许null key和null value,HashMap允许。
- Hashtable是线程安全的,HashMap不是线程安全的
- HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
- Hashtable继承自Dictionary,HashMap继承自AbstractMap。
- 两者都实现了Map接口
-
HashTable如何保障线程安全
- 查看源码,发现对外提供的public方法,几乎全部加上了synchronized关键字
- Hashtable的性能在多线程环境下会非常低效
- 建议大家在多线程环境下抛弃Hashtable,改用ConcurrentHashMap
-
Hashtable的初始化
public Hashtable() { this(11, 0.75f); } public Hashtable(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load: "+loadFactor); if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry[initialCapacity]; threshold = (int)(initialCapacity * loadFactor); }
- 在默认构造方法中,调用了Hashtable(int initialCapacity, float loadFactor)方法,初始Hashtable的容量为11,负载因子为0.75,那么初始阈值就是8。这点和HashMap很不同,HashMap在初始化时,table的大小总是2的幂次方,即使给定一个不是2的幂次方容量的值,也会自动初始化为最接近其2的幂次方的容量
-
Hashtable的put方法的实现
public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); } // Makes sure the key is not already in the hashtable. Entry tab[] = table; int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length; for (Entry
e = tab[index] ; e != null ; e = e.next) { if ((e.hash == hash) && e.key.equals(key)) { V old = e.value; e.value = value; return old; } } modCount++; if (count >= threshold) { // Rehash the table if the threshold is exceeded rehash(); tab = table; index = (hash & 0x7FFFFFFF) % tab.length; } // Creates the new entry. Entry e = tab[index]; tab[index] = new Entry (hash, key, value, e); count++; return null; } - 实现步骤和思路:
- 禁止null value插入
- 根据key的hashCode值 与 0x7FFFFFFF求与后得到新的hash值,然后计算其在table中的索引下标
- 在索引下标下遍历链表,查找key是否已存在,存在则更新value值
- 如果不存在,判断table.count是否超过阈值,超过则重新rehash,将原元素全部拷贝到新的table中,并重新计算索引下标。rehash后,容量是以前的2倍+1的大小,这点也和HashMap不同,HashMap是2倍。
- 插入元素时直接插入在链表头部
- 更新元素计数器
- 实现步骤和思路:
5.https 握手过程?
http和https 握手过程详解
6.TCP为什么需要三次握手?
- 为了实现可靠数据传输, TCP 协议的通信双方, 都必须维护一个序列号, 以标识发送出去的数据包中, 哪些是已经被对方收到的。 三次握手的过程即是通信双方相互告知序列号起始值, 并确认对方已经收到了序列号起始值的必经步骤
- 如果只是两次握手, 至多只有连接发起方的起始序列号能被确认, 另一方选择的序列号则得不到确认
7.常见加密算法?
常见的加密算法
8.讲一讲你熟悉的开源框架的源码?
9.Rxjava线程切换的原理?
详解 RxJava2 的线程切换原理
10.多线程同步?
11.怎么优化数据库?
Android Sqlite 优化
12.讲一讲Dart语言的优势?
13.Flutter开发过程中遇到了那些问题?
技术面 第二轮
1.首先介绍一下自己
2.讲一讲你做的项目的核心贡献
3.TCP 长链接,心跳包问题
- TCP 长链接,心跳包