baidu

2023-05-16

1.hashmap的底层原理,和hashtable的区别
put():对key的hashCode做hash操作,然后再计算在bucket中的index;如果没碰撞直接放到bucket里; 如果碰撞了,以链表的形式存在buckets后; 如果节点已经存在就替换old value(保证key的唯一性)
如果bucket满了就要扩容。
get():通过对key的hashCode()进行hashing,并计算下标( n-1 & hash),从而获得buckets的位置。如果产生碰撞,则利用key.equals()方法去链表中查找对应的节点。
它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。
jdk1.8及以上版本引入了红黑树,当链表的长度大于或等于8的时候则会把链表变成红黑树,以提高查询效率
扩容的问题:
负载因子越大,导致哈希冲突的概率也就越大,负载因子越小,浪费的空间也就越大(负载因子0.75,出始容量16)
(1)当多个线程同时发现hashMap需要调整大小,容易导致条件竞争,进而死锁。
(2)rehash操作是耗时操作。
HashMap和Hashtable的区别
(1)HashMap是线程不安全的,HashTable是线程安全的
(2)HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行
(3)单线程环境下Hashtable比HashMap

2.并发集合有哪些?
ConcurrentHashMap:线程安全的HashMap的实现
CopyOnWriteArrayList:线程安全且在读操作时无锁的ArrayList
CopyOnWriteArraySet:基于CopyOnWriteArrayList,不添加重复元素
ArrayBlockingQueue:基于数组、先进先出、线程安全
LinkedBlockingQueue:基于链表实现,读写各用一把锁,在高并发读写操作都多的情况下,性能优于ArrayBlockingQueue

3.ConcurrentHashMap
HashMap在多线程环境下存在线程安全问题,一般在多线程的场景,我都会使用好几种不同的方式去代替:
(1)使用Collections.synchronizedMap(Map)创建线程安全的map集合;
(2)Hashtable
(3)ConcurrentHashMap
出于线程并发度的原因,我都会舍弃前两者使用最后的ConcurrentHashMap,他的性能和效率明显高于前两者。
Collections.synchronizedMap内部维护了一个普通对象Map,还有排斥锁mutex,创建出synchronizedMap之后,再操作map的时候,就会对方法上锁
Hashtable在对数据操作的时候都会上锁,所以效率比较低下,Hashtable在我们put 空值的时候会直接抛空指针异常,但是HashMap却做了特殊处理
如果键使用null值,就会使得其无法判断对应的key是不存在还是为空,因为你无法再调用一次contain(key)来对key是否存在进行判断,ConcurrentHashMap同理。
ConcurrentHashMap
jdk1.7底层是基于 数组 + 链表 组成的,put方法采用了分段锁技术,其中Segment继承于ReentrantLock。由于HashEntry中的 value 属性是用 volatile 关键词修饰的
get方法是非常高效的,因为整个过程都不需要加锁。
数组加链表的方式,我们去查询的时候,还得遍历链表,会导致效率很低,这个跟jdk1.7的HashMap是存在的一样问题,所以他在jdk1.8完全优化了。
jdk1.8底层是基于 数组 + 链表 +红黑树,抛弃了原有的 Segment 分段锁,而采用了 CAS + synchronized 来保证并发安全性。
CAS 是乐观锁的一种实现方式,是一种轻量级锁,CAS 操作的流程是线程在读取数据时不进行加锁,在准备写回数据时,比较原值是否修改,
若未被其他线程修改则写回,若已被修改,则重新执行读取流程。这是一种乐观策略,认为并发操作并不总会发生。
CAS很经典的ABA问题,就是说来了一个线程把值改回了B,又来了一个线程把值又改回了A,对于这个时候判断的线程,就发现他的值还是A,
所以他就不知道这个值到底有没有被人改过,其实很多场景如果只追求最后结果正确,这是没关系的。用版本号去保证就好了,就比如说,
我在修改前去查询他原来的值的时候再带一个版本号,每次判断就连值和版本号一起判断,判断成功就给版本号加1。
比如时间戳也可以,查询的时候把时间戳一起查出来,对的上才修改并且更新值的时候一起修改更新时间,这样也能保证
synchronized 获取锁的方式,JVM 使用了锁升级的优化方式,就是先使用偏向锁优先同一线程然后再次获取锁,如果失败,就升级为 CAS 轻量级锁,
如果失败就会短暂自旋,防止线程被系统挂起。最后如果以上都失败就升级为重量级锁。

4.如何保证线程安全?有哪些方式
(1)synchronized同步关键字
(2)lock接口
(3)cas乐观锁(AtomicInteger、AtomicLong、AtomicBoolean)
(4)ThreadLocal实现多个线程之间的数据隔离

5.syschronized 与 Lock区别?
(1)syschronized是一个关键字而Lock是一个接口
(2)Synchronized 使用过后,会自动释放锁,而Lock需要手动上锁、手动释放锁。(
(3)Lock提供了更多的实现方法,而且 可响应中断、可定时, 而synchronized 关键字不能响应中断;
(4)synchronized关键字是非公平锁,Lock的子类ReentrantLock默认是非公平锁,但是可通过一个布尔参数的构造方法实例化出一个公平锁;(公平锁就是:先等待的线程,先获得锁。)
(5)synchronized无法判断,是否已经获取到锁,而Lock通过tryLock()方法可以判断,是否已获取到锁;
(6)Lock可以通过分别定义读写锁提高多个线程读操作的效率。
(7)二者的底层实现不一样:synchronized是同步阻塞,采用的是悲观并发策略;Lock是同步非阻塞,采用的是乐观并发策略(底层基于volatile关键字和CAS算法实现)

6.voliate关键字
voliate关键字轻量级的同步机制,作用主要有:保证内容可见性、禁止指令重复排序、不保证原子性,一个线程修改变量后,对其他线程可见,用于多个线程读一个线程写的场景。

7.并发和并行的区别和理解
相同点:
并发和并行的目标都是最大化CPU的使用率
不同点:
(1)并行在多处理器系统中存在,而并发可以在单处理器和多处理器系统中都存在
(2)并行要求程序能够同时执行多个操作,而并发只是要求程序“看着像是”同时执行多个操作,其实是交替执行。

8.wait()和notify()方法的使用,notify 关键字
线程等待wait和通知notify/notifyAll,主要用于多线程之间的通信协作,而且这两个方法都是属于Object类,任何对象都可以调用这两个方法。
当在一个实例对象上调用了wait()方法之后,当前线程就会释放掉它获取到的锁资源,将锁资源让给其他线程去竞争,然后当前线程会被阻塞挂起,
直到另外的线程调用了该对象的notify()方法,处于等待状态的线程才得以继续进行,notify 会随机的唤醒被阻塞到该共享对象上的一个线程,
而 notifyAll() 则会唤醒所有在该共享对象上被wait 方法阻塞而陷入等待状态的线程。
wait() 和 notify()必须配合synchrozied关键字使用,wait()会释放锁,而notify()不释放锁。
sleep会使当前线程睡眠指定时间,不释放锁
yield会使当前线程重回到可执行状态,等待cpu的调度,不释放锁
某线程.join()时会使当前线程等待某线程执行完毕再结束.释放锁

9.为什么要使用线程池,线程池的工作原理,线程池的参数作用,含义
好处:
重用存在的线程,减少对象创建、消亡的开销,提高性能。
可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
提供定时执行、定期执行、单线程、并发数控制等功能。

原理:
当一个任务通过execute(Runnable)方法添加到线程池时:
Ø 线程数量小于corePoolSize,新建线程(核心)来处理被添加的任务;
Ø 线程数量大于等于 corePoolSize,存在空闲线程,使用空闲线程执行新任务;
Ø 线程数量大于等于 corePoolSize,不存在空闲线程,新任务被添加到等待队列;如果添加成功则等待空闲线程,如果添加失败:
线程数量小于maximumPoolSize,新建线程执行新任务;
线程数量等于maximumPoolSize,拒绝此任务。
Ø 当线程数大于核心线程数事,超过KeepAliveTime(闲置时间),线程会被回收,最终会保持corePoolSize个线程。

七大参数
1.corePoolSize:线程池中的常驻核心线程数
2.maxinumPoolSize:线程池中能够容纳同时执行的最大线程数,此值必须大于等于一
3.keepAliveTime:多余的空闲线程的存活时间。
当前线程池数量超过corePoolSize时,当空闲时间达到keepAliveTime时,多余空闲线程会被销毁直到只剩下corePoolSize个线程为止。
4.unit:keepAliveTime的单位
5.workQueue:任务队列,被提交但是尚未被执行的任务。
6.threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可。
7.handler:拒绝策略,表示当队列满了并且工作线程-大于等于线程池的数量最大线程数

拒绝策略:
1.直接抛出异常
2.直接默默丢失
3.策略丢弃任务队列中等待事件最长的
4.谁提交任务谁来执行这个任务

10.线程跟进程的区别?
1、定义不一样,进程是执行中的一段程序,而一个进程中执行中的每个任务即为一个线程。
2、一个线程只可以属于一个进程,但一个进程能包含多个线程。
3、线程无地址空间,它包括在进程的地址空间里。
4、线程的开销或代价比进程的小。

11.handler机制(线程之间的通信怎么实现的及其原理)
UI线程创建时,就创建了一个Looper,Looper内部维护这一个MessageQueue。Looper通过开启一个while(true)死循环来轮询MessageQueue中的Message。当Looper轮询到Message时,就分发此Message。Handler在子线程发送消息到MessageQueue,Message被Looper取出来后,分发给handler的handleMessage方法来处理。

12.一个线程有几个looper以及怎么保证,怎么初始化
一个线程中只能有一个Looper,通过ThreadLocal来保证
Looper.prepare();
Looper.loop();

13.ThreadLocal的原理
ThreadLocal在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
实现线程安全,非线程安全的对象使用ThreadLocal之后就会变得线程安全,因为每个线程都会有一个对应的实例。 承载一些线程相关的数据,避免在方法中来回传递参数。
在每个Thread中包含一个ThreadLocalMap,ThreadLocalMap的key是ThreadLocal的对象,value是独享数据。

14.多个Handler同时发消息,怎么辨别是谁
message.what用来识别不同的消息,多个handler发送消息时通过message.what加以区分

15.有用过aidl吗?及原理
AIDL(Android Interface Define Language)是一种IPC通信方式,我们可以利用它来定义两个进程相互通信的接口。他是基于Service实现的一种线程间通信机制。它的本质是C/S架构的,需要一个服务器端,一个客户端。
(1)创建aidl:工程中添加一个module,作为aidl的服务端在aidlserver中创建aild目录, 同时创建一个aidl文件,声明了一个接口,里面定义了aidl服务器端暴露给客户端调用的方法。手动编译程序,生成aidl对应的Java代码
(2)实现接口,并向客户端放开接口:创建了一个service,并在service内部声明了一个IBinder对象,它是一个匿名实现的IAidlInterface.Stub的实例
(3)客户端调用aidl:在客户端跟服务器一样,新建aidl目录,将服务器端的aidl拷贝到客户端,拷贝后的客户端的aidl文件包目录必须与服务器端保持一致,拷贝完后同样时编译工程,让客户端也生成对应的java文件,在Activity的onCreate中绑定服务后进行调用。

AIDL可使用的参数类型
基本数据类型、引用数据类型、自定义数据类型(必须实现Parcelable接口)

11.A跟B在同一个进程里,A能创建B吗,进程间通信有哪些,他们之间的区别,进程间通信的内存交换方式有哪些,进程间通信机制
可以创建。
不同的进程之间以某种方式进行数据交换就是进程通信。
进程间通信有:管道、消息队列、共享内存和 Socket 、Binder等 IPC 机制。
(1)管道/消息队列:信息复制两次,额外的CPU消耗;不合适频繁或信息量大的通信;
(2)共享内存:无须复制,共享缓冲区直接附加到进程虚拟地址空间,速度快;但进程间的同步问题操作系统无法实现,必须各进程利用同步工具解决;
(3)Socket:作为更通用的接口,传输效率低(涉及io读写),主要用于不通机器或跨网络的通信;
(4)Binder:是​ Android系统中跨进程通讯(IPC)的一种方式,Android中ContentProvider、Intent、aidl都是基于Binder。1…Binder使用mmap机制,只拷贝了一次数据,性能上仅次于共享内存;2.采用Client/Server架构,实现面向对象的调用方式,调用如同调用Java对象,使用简单;3.为每个App分配了UID/PID来鉴别身份标识,通信时检测UID/PID进行有效性检测,提高了安全性)

12.设计一个音乐播放器,service怎么启动
startService与bindService同时启动,可通过调用 startService()启动该服务,让服务无限期运行;此外,还可通过调用 bindService() 使客户端绑定到服务。Activity 便可启动服务进行音乐播放,即使用户离开应用,音乐播放也不会停止。 然后,当用户返回应用时,Activity 可绑定到服务,重新获得回放控制权。

13.内存泄漏的本质,你是怎么排查的,内存泄露的场景以及解决方法,怎么优化。
内存泄漏(Memory Leak)是指某些对象已经不再使用了,但却无法被垃圾回收器回收内存,还一直占用着内存空间的现象,这就导致这一块内存泄露了。本质就是生命周期短的对象被生命周期长的对象引用了,导致生命周期短的对象无法及时被垃圾回收器回收。

工具:AndroidStudio Memory-profiler/LeakCanary

防止内存泄漏:
(1)资源性对象未关闭(例如Bitmap、IO)对于资源性对象不再使用时,应该立即将其关闭
(2)注册对象未注销(例如BraodcastReceiver、EventBus)应该在Activity销毁时及时注销。
(3)类的静态变量持有大数据对象。尽量避免使用静态变量存储数据,特别是大数据对象,建议使用数据库存储。
(4)单例、非静态内部类、Handler造成的内存泄漏,优先使用Application的Context,如需使用Activity的Context,考虑使用静态内部类和弱引用。
(5)WebView可能存在内存泄漏的问题。为WebView开启一个独立的进程,使用AIDL与应用的主进程进行通信,选择合适的时机进行销毁

防止内存抖动:
(1)避免频繁创建对象,如:避免在for语句中创建大量对象
(2)需要频繁使用的对象,可以通过缓存池复用,避免重复创建、释放

字符串相加或者拼接通过StringBuilder替代,较少创建String对象节省内存
使用SpareArray、ArrayMap替代HashMap
图片优化
使用Glide框架

14.图片优化方案有哪些
(1)格式RGB_565 每个像素2个字节
(2)质量压缩 Bitmap.compress
(3)二次采样 BitmapFactory.Options.inSampleSize
(4)转码成Webp格式 Webp是谷歌提供的一种支持有损压缩和无损压缩的图片文件格式,而且可以提供比JPEG或PNG更好的压缩
(5)内存-文件-网络缓存
(6)Bitmap复用

15.Android自定义控件有哪些实现方式
(1)继承现有控件(TextView/ImageView/LinearLayout),对其控件的功能进行拓展
(2)将现有控件进行组合,实现功能更加强大控件。
(3)重写View/ViewGroup实现全新的控件

16.自定义View,View 绘制流程
View的工作流程主要是指oneasure、onLayout、onDraw这三大流程,即测量、布局和绘制,其中measure确定View的测量宽/高,layout确定View的最终宽/高和四个顶点的位置,而draw则将View绘制到屏幕上

17.Andriod事件分发机制
View事件分发本质就是对MotionEvent事件分发的过程。即当一个MotionEvent发生后,系统将这个点击事件传递到一个具体的View上
点击事件的传递顺序:Activity(Window)→ViewGroup→ View
事件分发过程由三个方法共同完成:
dispatchTouchEvent:用来进行事件的分发。如果事件能够传递给当前View,那么此方法一定会被调用,返回结果受当前View的onTouchEvent和下级View的dispatchTouchEvent方法的影响,表示是否消耗当前事件
onInterceptTouchEvent:在上述方法内部调用,对事件进行拦截。该方法只在ViewGroup中有,View(不包含 ViewGroup)是没有的。一旦拦截,则执行ViewGroup的onTouchEvent,在ViewGroup中处理事件,而不接着分发给View。且只调用一次,返回结果表示是否拦截当前事件
onTouchEvent: 在dispatchTouchEvent方法中调用,用来处理点击事件,返回结果表示是否消耗当前事件

如何解决View的事件冲突 ? 举个开发中遇到的例子 ?
常见开发中事件冲突的有ScrollView与RecyclerView的滑动冲突、RecyclerView内嵌同时滑动同一方向
滑动冲突的处理规则:
对于由于外部滑动和内部滑动方向不一致导致的滑动冲突,可以根据滑动的方向判断谁来拦截事件。
对于由于外部滑动方向和内部滑动方向一致导致的滑动冲突,可以根据业务需求,规定何时让外部View拦截事件,何时由内部View拦截事件。
对于上面两种情况的嵌套,相对复杂,可同样根据需求在业务上找到突破点。
滑动冲突的实现方法:
外部拦截法:指点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,否则就不拦截。具体方法:需要重写父容器的onInterceptTouchEvent方法,在内部做出相应的拦截。
内部拦截法:指父容器不拦截任何事件,而将所有的事件都传递给子容器,如果子容器需要此事件就直接消耗,否则就交由父容器进行处理。具体方法:需要配合requestDisallowInterceptTouchEvent方法。

18.Android系统中Service和IntentService的区别,IntentService的原理
Service 是长期运行在后台的应用程序组件,不是一个单独的进程,它和应用程序在同一个进程中,也不是一个线程,它和线程没有任何关系,
所以它不能直接处理耗时操作。如果有耗时操作就必须开启一个单独的线程来处理。
IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,
启动 IntentService 的方式和启动传统 Service 一样,具有高优先级,适合高优先级的后台任务,且不容易被系统杀死,任务执行后会自动停止。
可以多次启动,每个耗时操作都会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,执行完第一个再执行第二个
IntentService在onCreate里面初始化了一个HandlerThread,每次调用onStartCommand的时候,通过mServiceHandler发送一个消息,
消息中包含我们的intent。然后在该mServiceHandler的handleMessage中去回调onHandleIntent(intent);当依次执行完任务后,
回调用 stopSelf销毁我们的Service.当任务完成销毁Service回调onDestory,在onDestroy中释放了我们的Looper

19.安卓的数据存储方式有哪些?
(1)使用SharedPreferences存储数据 轻型的数据存储方式,存储的key-value键值对数据
(2)文件存储数据 写入和读取文件I/O
(3)SQLite数据库存储数据 轻量级嵌入式数据库,用来存储大量复杂的关系数据
(4)使用ContentProvider存储数据 主要用于应用程序之间进行数据交换

20.补间动画跟属性动画的区别
补间动画
只能够为View添加动画,功能比较单调,只有四种动画(透明度,旋转,倾斜和位移),View的属性没有改变,其位置与大小都不变
属性动画
可以为一个对象的任意属性添加动画,对象自己的属性会被真的改变。
插值器(Interpolator)决定值的变化规律(匀速、加速),即决定的是变化趋势;而接下来的具体变化数值则交给估值器
ValueAnimator 是 ObjectAnimator 的父类,他两之间的区别是,ObjectAnimator 在ValueAnimator 的基础上,通过反射技术实现了动画功能,也就像我刚刚所举的例子,子要给了 ObjectAnimator 两个值(from,to),在确定动画类型(“scale,translate”),他就能自动生成动画。
与之形成区别,虽然我们同样需要给 ValueAnimator 传递起始和最终两个值,但是 ValueAnimator 并不会自动去执行什么,而是会通过addUpdateListener的监听方法,在时间插值器的作用下,有序的返回一连串数值,然后我们就可以通过这些数值,对控件进行设置。

21.常用的布局有哪些
相对布局、线性布局、FrameLayout(帧布局)
约束布局(ConstraintLayout)
app:layout_constraintTop_toTopOf=“” 我的顶部和谁的顶部对齐
app:layout_constraintBottom_toBottomOf=“” 我的底部和谁的底部对齐
app:layout_constraintLeft_toLeftOf=“” 我的左边和谁的左边对齐
app:layout_constraintRight_toRightOf=“” 我的右边和谁的右边对齐
app:layout_constraintStart_toStartOf=“” 我的开始位置和谁的开始位置对齐
app:layout_constraintEnd_toEndOf=“” 我的结束位置和谁的结束位置对齐
app:layout_constraintTop_toBottomOf=“” 我的顶部位置在谁的底部位置
app:layout_constraintStart_toEndOf=“” 我的开始位置在谁的结束为止
layout_constraintBaseline_toBaselineOf来实现,它的意思就是这个控件的基线与谁的基线对齐

22.App里所有textveiw的字体大小以及布局都一样 你可以用什么方法去实现
使用style

23.布局文件里面怎么复用其他文件
include:引入重复使用的相同布局
merge:减少include布局的层级,将子元素直接添加到merge标签的parent中,对merge标签设置的属性是无效的。
ViewStub:其实就是一个宽高都为0的一个View,它默认是不可见的,只有通过调用setVisibility函数或者Inflate函数才会将其要装载的目标布局给加载出来,inflate只能被调用一次

24.序列化,Serializable和parceable区别
(1)读写方面:Serializable是通过使用IO流的形式将数据读写入在硬盘上,而Parcelable则是在内存中直接进行读写。
(2)Serializable在序列化的时候会产生大量的临时变量,Parcelable是以Ibinder作为信息载体的.在内存上的开销比较小
(3)Serializable效率低,而Parcelable效率高
如果是在内存中使用序列化用Parcelable,如果是磁盘中使用则用 Serializable

25.类加载
当一个ClassLoader去加载一个类的时候,它会去判断该类是否已经加载,如果没有,它不会马上去加载,而是委托给父加载器进行查找,
这样递归一直找到最上层的ClassLoader类,如果找到了,就直接返回这个类所对应的Class对象,如果都没有加载过,就从顶层的ClassLoader去开始依次向下查找,
每个加载器会从自己规定的位置去查找这个类,如果没有,最后再由请求发起者去加载该类。PathClassLoader
双亲委派机制的好处:
1:避免重复加载,如果已经加载过一次Class,就不需要再次加载,而是先从缓存中直接读取。
2:更加安全,因为虚拟机认为只有两个类名一致并且被同一个类加载器加载的类才是同一个类,所以这种机制保证了系统定义的类不会被替代。

26.java面向的三大特征
1)封装 把属性设为private,隐藏内部细节限制外部直接访问,提供公共的get和set方法间接访问,提升安全性。
(2)继承 子类继承父类,所有非私有的属性和方法(不包含构造器和主方法)Java只能单一继承(可以通过多重继承来实现多继承)
(3)多态 就是同一个接口,使用不同的实例而执行不同操作
要有继承或实现关系,要有方法的重写,要有父类引用指向子类对象
成员变量编译看父类,运行看父类;成员方法编译看父类,运行看子类

27.Java的设计模式?
(1)单一职责原则——一个类应该只负责一项职责
(2)迪米特原则——一个对象应该对其他对象保持最少的了解。
(3)里氏代换原则——所有引用基类(父类)的地方必须能透明地使用其子类的对象。
(4)接口隔离原则——一个类对另一个类的依赖应该建立在最小的接口上
(5)依赖倒置原则——高层模块不应该依赖低层模块,二者都应该依赖其抽象
(6)开闭原则——一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

28.单独说下单例模式
单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例
(1)饿汉式。避免了线程同步问题,没有达到懒加载的效果
(2)懒汉式。(双重检查,线程安全;延迟加载;效率较高)
(3)静态内部类。避免了线程不安全,延迟加载,效率高。
(4)枚举。不仅能避免多线程同步问题,而且还能防止反序列化重新创建新的对象。

双重检查加锁机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法过后,先检查实例是否存在,如果不存在才进入下面的同步块,这是第一重检查。进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。
双重检查加锁机制的实现会使用一个关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。

节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
使用场景
(1)需要频繁的进行创建和销毁的对象;
(2)创建对象时耗时过多或耗费资源过多,但又经常用到的对象;
(3)工具类对象;
(4)频繁访问数据库或文件的对象。

29.string、stringbuffer、stringbuilder之间的区别
String的值是不可变的,每次操作都会生成大量对象,浪费空间
StringBuffer对象的值是可变的,是线程安全的,可以在多线程下运行
StringBuilder值是可变的,不能在多线程下运行,运行速度快

30.泛型中那个extension 跟super的用法区别?就是说怎么设置上界下界的意思
extends也称为上界通配符,就是指定上边界。即泛型中的类必须为当前类的子类或当前类。
super也称为下届通配符,就是指定下边界。即泛型中的类必须为当前类或者其父类。
只能读取,不能修改,就是协变,就是生产者 java : ? extends
只能修改,不能获取,就是逆变,就是消费者 java: ? super

31.动态代理有涉及过吗 一般怎么用的
代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问
1、静态代理只代理一个类,而动态代理是代理接口下的多个实现类
2、静态代理在编译时就知道要代理的类,而动态代理是在运行期动态生成的代理类。
3、动态代理类不需要实现接口,但是委托类还是需要实现接口。

32.黄油刀有用过没?黄油刀的优势和劣势是什么?除了黄油刀意外有没有用过其他的?
ButterKnife 是一个 Android 系统的 View 注入框架,工作原理:
(1)首先会扫描java代码中所有通过ButterKnife设置的注解比如@Bind,@OnClick等。
(2)当发现一个类中含有任何一个注解时,ButterKnifeProcessor会生通过javapot成一个java类,这个类实现了ViewBinder接口。
这个ViewBinder类中包含了所有对应的代码,比如@Bind注解对应的findViewByid(),@OnClick对应的setOnClickListener等等。
(3)最后当Actvity启动通过ButterKnife调用bind方法绑定时,ButterKnife会去加载对应的ViewBinder类并调用它们的bind方法。
优势:
强大的View绑定和Click事件处理功能,简化了代码,提升开发效率
运行时不会影响APP的效率
劣势:
无法在Android项目的library模块中使用
ViewBinding DataBingding

33.网络协议了解么?Https的整个通讯过程讲一下,Http和https比较区别
①客户端发起HTTPS请求
用户在浏览器里输入一个https网址,然后连接到服务器的443端口。
②服务端的配置
采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请,区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面,这套证书其实就是一对公钥和私钥。
③传送服务器的证书给客户端
证书里其实就是公钥,并且还包含了很多信息,如证书的颁发机构、过期时间等。
④客户端解析验证服务器证书
这部分工作是由客户端的TLS来完成的,首先会验证公钥是否有效,比如:颁发机构、过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随机值,然后用证书中公钥对该随机值进行非对称加密。
⑤客户端将加密信息传送服务器
这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。
⑥服务端解密信息
服务端将客户端发送过来的加密信息用服务器私钥解密后,得到了客户端传过来的随机值。
⑦服务器加密信息并发送信息
服务器将数据利用随机值进行对称加密,再发送给客户端。
⑧客户端接收并解密信息
客户端用之前生成的随机值解密服务段传过来的数据,于是获取了解密后的内容。

HTTP协议以明文方式发送内容,不提供任何方式的数据加密。HTTP协议不适合传输一些敏感信息
https则是具有安全性的ssl加密传输协议。http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。并且https协议需要到ca申请证书。HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。

34.GC
可以当做GC roots的对象有以下几种:
(1)虚拟机栈中的引用的对象。
(2)方法区中的类静态属性引用的对象。
(3)方法区中的常量引用的对象。
(4)本地方法栈中JNI的引用的对象。
对象存活判断
(1)引用计数:每个对象有个计数器,多一个引用加1,少一个减1,为0时回收
(2)对象可达性分析:到GC Roots没有任何引用链
垃圾回收算法种类,内存回收的方法论
(1)标记-清除算法,标记需要回收的对象,然后清除,会产生内存碎片
(2)复制算法,把内存分为两半,一半用来使用,当需要回收时,把存活的对象复制到另一半,限制了内存空间
(3)标记-整理算法,清除完之后移动碎片
(4)分代回收算法:年轻代使用复制算法,老年代使用标记-整理算法,
内存回收策略可以从以下几个维度来理解:
(1)串行&并行
串行:单线程执行内存回收工作。十分简单,无需考虑同步等问题,但耗时较长,不适合多cpu。
并行:多线程并发进行回收工作。适合多CPU,效率高。
(2)并发& stop the world
stop the world:jvm里的应用线程会挂起,只有垃圾回收线程在工作进行垃圾清理工作。简单,无需考虑回收不干净等问题。
并发:在垃圾回收的同时,应用也在跑。保证应用的响应时间。会存在回收不干净需要二次回收的情况。
(3)压缩&非压缩&copy
压缩:在进行垃圾回收后,会通过滑动,把存活对象滑动到连续的空间里,清理碎片,保证剩余的空间是连续的。
非压缩:保留碎片,不进行压缩。
copy:将存活对象移到新空间,老空间全部释放。(需要较大的内存。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

baidu 的相关文章

随机推荐

  • 使用 lvreduce 对逻辑卷做减容缩容操作及注意要点

    1 背景 Linux 系统运维管理过程中 xff0c 有时候会遇到某个逻辑卷所分配的容量较大 xff0c 实际使用量又不多 xff0c 导致剩余较多浪费了 此时如果有其他的逻辑卷需要扩容 xff0c 出于资源利用最大化的考虑 xff0c 会
  • ps aux 进程状态为 I (大写i)

    系统使用 ps aux 查看进程时 xff0c 发现有状态为 I 大写i 的进程 xff0c 暂无发现由于这个状态导致的问题 进程状态 I xff0c 表示task idle xff0c 即空闲的任务 xff08 进程 xff09 xff0
  • android网络框架OkHttp之get请求(源码初识)

    转载请标明出处 xff1a http blog csdn net iamzgx article details 51477877 xff1b 本文出自 iGoach的博客 概括 OkHttp现在很火呀 于是上个星期就一直在学习OkHttp框
  • 学会Retrofit+OkHttp+RxAndroid三剑客的使用,让自己紧跟Android潮流的步伐

    转载请标明出处 xff1a http blog csdn net iamzgx article details 51607387 本文出自 iGoach的博客 概括 在上一篇博客android网络框架OkHttp之get请求 xff08 源
  • 手动缓存Retrofit+OkHttp响应体,不再局限于Get请求缓存

    转载请标明出处 xff1a http blog csdn net iamzgx article details 51764848 本文出自 iGoach的博客 概括 这篇博客是接着上一篇博客学会Retrofit 43 OkHttp 43 R
  • 哪个才是Android工程构建时的gradle版本?gradle-wrapper.properties还是build.gradle的buildscript说了算?

    先说谜底 xff0c gradle wrapper properties说了算 xff08 1 xff09 build gradle的buildscript里的buildscript dependencies的com android too
  • cocos2d-js之入门篇

    转载请标明出处 xff1a http blog csdn net iamzgx article details 54232599 本文出自 iGoach的博客 cocos2d js xff0c 至今日 xff0c 也马马虎虎算接触了一个星期
  • 微信小程序-入门篇

    转载请标明出处 xff1a http blog csdn net iamzgx article details 72615506 本文出自 iGoach的博客 前言 2017年1月9日 xff0c 微信小程序发布 这也标志着FaceBook
  • 使用OkHttp上传图片

    简介 上传图片是一个APP的常见功能 xff0c 可以是通过OOS上传到阿里云 xff0c 也可以直接上传到Server后台 xff0c OOS有提供相应的SDK xff0c 此处忽略 下面通过OkHttp来实现图片的上传 代码 直接上代码
  • 简单说说如何把json或者txt文件转换为db

    前言 最近在Github上找到一个中国城市的json文件 xff0c 虽然也有db文件 xff0c 但是想通过这个json文件生成自己的数据库表 下面就简单来转换成自己的数据库 准备json 在Github找到一个下面json表 34 sp
  • 2018年7月面试记录

    MRCM 聊天缓存如何实现的聊天重发如何实现如何保持长连接心跳简述TCP协议写一个自己最擅长的设计模式 ZHYT finish会立马销毁activity吗view的生命周期activity结束了HandlerQueue如何处理Handler
  • Android面向AOP之AspectJ的使用篇

    前言 AOP xff0c 它不是一门新语言 xff0c 是一种面向切面的思想 它主要的作用是把一些具有相同属性或者相同功能的代码抽离出来形成一个切面 xff0c 从而实现面向切面编程 xff01 而AspectJ就是基于Java语言实现AO
  • 仿拉勾首页之Behavior的学习

    前言 最近在找工作 xff0c 于是打开拉勾 xff0c 看了看首页 xff0c 交互做的还是不错的 先来看看拉勾效果 然后最终实现的效果 布局是图片直接用 xff0c 所以会失真 实现思路 首先这个是一个MD的效果 xff0c 可以使用自
  • Java中Collections类方法常用合集

    目录 1 Collections sort list 2 Collections reverse list 3 Collections shuffle list 4 Collections swap List list int i int
  • 解决Slf4j日志不打印问题

    日志不打印的问题 xff0c 很让人头疼 xff0c 也是我们经常遇到的问题 日常站点状态巡检时发现有异常日志 xff0c 定位到日志位置 xff0c 看其上线文自定义输出的日志时却发现 xff0c 自己加的日志都没输出 排查了一下初步定位
  • Android Studio 配置Gradle总结

    一 xff0c 问题 xff1a 换个新电脑安装完Android Sutdio第一次打开一个工程巨慢怎么办 xff1f 手动配置Gradle Home为什么总是无效 明明已经下载了Gradle xff0c 配置了gradle home 为什
  • android 指纹识别 之 BiometricPrompt的简单使用教程

    1 使用android api 28的sdk创建一个新的项目 创建完成后 xff0c 在build gradle中查看是否正确 2 在AndroidManifest xml中添加用户权限 lt uses permission android
  • Linux常用命令

    expect except是一种自动交互语言 xff0c 能实现在shell脚本中为scp和ssh等自动输入密码自动登录 span class token comment usr bin expect span span class tok
  • 使用 Acegi 保护 Java 应用程序,第 5 部分: 保护 JSF 应用程序中的 JavaBean

    Bilal Siddiqui 在这篇文章中总结了 本系列 xff0c 演示了如何用 Acegi 在 JSF 应用程序中保护对 JavaBean 的访问 可以使用多种方式配置安全 bean xff0c 包括直接在 JSF 标签中使用受 Ace
  • baidu

    1 hashmap的底层原理 和hashtable的区别 put xff1a 对key的hashCode做hash操作 xff0c 然后再计算在bucket中的index xff1b 如果没碰撞直接放到bucket里 xff1b 如果碰撞了