文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

android-7 面试知识点

2022-06-06 14:02

关注

1、说说Glide中的with方法2、什么是线程安全?保障线程安全有哪些手段?3、说说TCP的三次挥手、四次挥手4、谈谈垃圾回收机制?5、手写单例模式中的懒汉双重锁代码6、LaunchMode及其使用场景7、请手写一个冒泡排序8、Activity的启动过程9、请大概说一下你了解的Service10、说一下你了解的广播11、请说一下内容提供者12、Handler原理13、OKHttp大概工作流程14、View和viewgroup区别15、Java 中堆和栈有什么区别?16、ArrayList和LinkedList有何区别?17、Java的四种引用及应用场景?18、 String, StringBuffer和StringBuilder区别19、请写一下Android中Fragment生命周期,以及各自作用20、Activity生命周期21、EventBus22、标注:序列化23、Android与js交互24、进程间通信有哪些方式25、面向对象编程的几大特性及其含义?26遇见过哪些运行时异常?异常处理机制知道哪些?27、Java中引用有几种类型?在Android中常用于什么情景?28、Okhttp中的拦截器以及作用29、Fragment与Activity通信和Fragment与Fragment之间的相互通信30、ANR如何产生,ANR如何避免31、面向对象编程的四大特性及其含义?32、String、StringBuffffer和StringBuilder的区别?33、String a=""和String a=new String("")的的关系和异同?34、Object的equal()和==的区别?35、装箱、拆箱什么含义?36、int和Integer的区别?37、什么是反射,有什么作用和应用?38、什么是内部类?有什么作用?静态内部类和非静态内部类的区别?39、fifinal、fifinally、fifinalize()分别表示什么含义39、重写和重载的区别?40、抽象类和接口的异同?41、为什么匿名内部类中使用局部变量要用fifinal修饰?42、Object有哪些公有方法?43、Java集合框架中有哪些类?都有什么特点 1、说说Glide中的with方法

Glide是一个比较高效的第三方加载图片的框架,不用担心内存溢出的问题。当我们加载一张大图,Glide不会直接将图片的完整尺寸全部加载到内存中,而是会自动判断ImageView的大小,然后只将ImageView计算出来的大小图片像素加载到内存中,帮助我们节省内存的开支。
它的核心代码是Glide.with(this).load(url).into(imageView);
with()方法可以接收Context、Activity或者Fragment类型的参数。也就是说我们选择的范围非常广,不管是在Activity还是Fragment中调用with()方法,都可以直接传this。那如果调用的地方既不在Activity中也不在Fragment中呢?也没关系,我们可以获取当前应用程序的ApplicationContext,传入到with()方法当中。注意with()方法中传入的实例会决定Glide加载图片的生命周期,如果传入的是Activity或者Fragment的实例,那么当这个Activity或Fragment被销毁的时候,图片加载也会停止。如果传入的是ApplicationContext,那么只有当应用程序被杀掉的时候,图片加载才会停止。

2、什么是线程安全?保障线程安全有哪些手段?

线程安全就是当多个线程访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替执行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那这个对象是线程安全的。保证线程安全可从多线程三特性出发:

原子性(Atomicity):单个或多个操作是要么全部执行,要么都不执行
Lock:保证同时只有一个线程能拿到锁,并执行申请锁和释放锁的代码
synchronized:对线程加独占锁,被它修饰的类/方法/变量只允许一个线程访问

可见性(Visibility):当一个线程修改了共享变量的值,其他线程能够立即得知这个修改
volatile:保证新值能立即同步到主内存,且每次使用前立即从主内存刷新;
synchronized:在释放锁之前会将工作内存新值更新到主存中

有序性(Ordering):程序代码按照指令顺序执行
volatile: 本身就包含了禁止指令重排序的语义
synchronized:保证一个变量在同一个时刻只允许一条线程对其进行lock操作,使得持有同一个锁的两个同步块只能串行地进入

3、说说TCP的三次挥手、四次挥手

(1)建立TCP连接:TCP的三次握手

客户端向服务端发送一个表示建立连接的报文段SYN报文段;一旦包含SYN报文段的IP数据报到达服务器主机,服务器从IP数据报中提取出TCP、SYN报文段,为该TCP连接分配需要的缓存和变量,并向客户端发送表示允许连接的报文段ACK;在收到ACK报文段之后,客户端也要给该连接分配缓存和变量,客户端向服务器再发送一个报文段ACK,表示对允许连接的报文段进行了确认。自此完成一次TCP连接。
第三次握手可以避免由于客户端延迟的请求连接的请求,使得服务端无故再次建立连接。

(2)断开TCP连接:TCP的四次挥手

由于TCP连接是全双工的,因此每个方向都必须单独关闭。客户端在数据发送完毕后发送一个结束数据段FIN,且服务端也返回确认数据段ACK,此时结束了客户端到服务端的连接;然后客户端接收到服务端发送的FIN,且服务端也收到了ACK之后,自此双方的数据通信完全结束。简单说来是 “先关读,后关写”,一共需要四个阶段:服务器读通道关闭->客户机写通道关闭->客户机读通道关闭->服务器写通道关闭。

4、谈谈垃圾回收机制?

回收算法有以下四种:
分代收集算法:是当前商业虚拟机都采用的一种算法,根据对象存活周期的不同,将Java堆划分为新生代和老年代,并根据各个年代的特点采用最适当的收集算法。
新生代:大批对象死去,只有少量存活。使用『复制算法』,只需复制少量存活对象即可。
复制算法:把可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用尽后,把还存活着的对象『复制』到另外一块上面,再将这一块内存空间一次清理掉。
老年代:对象存活率高。使用『标记—清理算法』或者『标记—整理算法』,只需标记较少的回收对象即可。
标记-清除算法:首先『标记』出所有需要回收的对象,然后统一『清除』所有被标记的对象。
标记-整理算法:首先『标记』出所有需要回收的对象,然后进行『整理』,使得存活的对象都向一端移动,最后直接清理掉端边界以外的内存。

5、手写单例模式中的懒汉双重锁代码

在这里插入图片描述

6、LaunchMode及其使用场景

standard 模式
这是默认模式,每次激活Activity时都会创建Activity实例,并放入任务栈中。使用场景:大多数Activity。
singleTop 模式
如果在任务的栈顶正好存在该Activity的实例,就重用该实例( 会调用实例的 onNewIntent() ),否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例,只要不在栈顶,都会创建新的实例。使用场景如新闻类或者阅读类App的内容详情页面。
singleTask 模式
如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的 onNewIntent() )。重用时,会让该实例回到栈顶,因此在它上面的实例将会被移出栈。如果栈中不存在该实例,将会创建新的实例放入栈中。使用场景如浏览器的主界面。不管从多少个应用启动浏览器,只会启动主界面一次,其余情况都会走onNewIntent,并且会清空主界面上面的其他页面,或者项目中的主界面。
singleInstance 模式
在一个新栈中创建该Activity的实例,并让多个应用共享该栈中的该Activity实例。一旦该模式的Activity实例已经存在于某个栈中,任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个应用,不管谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒,将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面,如果用于中间页面,跳转会有问题,比如:A -> B (singleInstance) -> C,完全退出后,在此启动,首先打开的是B

7、请手写一个冒泡排序
	冒泡排序。
	特点:相邻两个元素进行比较。
		内循环结束一次,最值出现在最后角标位。
	*/
	public static void bubbleSort(int[] arr)
	{
		for(int x=0; x<arr.length-1; x++)
		{
			for(int y=0; yarr[y+1])
				{
					int temp = arr[y];
					arr[y] = arr[y+1];
					arr[y+1] = temp;
				}
			}
		}
	}
8、Activity的启动过程

Activity的启动过程,我们可以从Context的startActivity说起,其实现是ContextImpl的startActivity,然后内部会通过Instrumentation来尝试启动Activity,这是一个跨进程过程,它会调用ams的startActivity方法,当ams校验完activity的合法性后,会通过ApplicationThread回调到我们的进程,这也是一次跨进程过程,而applicationThread就是一个binder,回调逻辑是在binder线程池中完成的,所以需要通过Handler H将其切换到ui线程,第一个消息是LAUNCH_ACTIVITY,它对应handleLaunchActivity,在这个方法里完成了Activity的创建和启动,接着,在activity的onResume中,activity的内容将开始渲染到window上,然后开始绘制直到我们看见。

9、请大概说一下你了解的Service

9.1 Service两种启动方式且对应的生命周期
9.1.1 startService 方式
通过startService启动后,service会一直无限期运行下去,只有外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁。
要创建一个这样的Service,你需要让该类继承Service类,然后重写以下方法:
onCreate()
1.如果service没被创建过,调用startService()后会执行onCreate()回调;
2.如果service已处于运行中,调用startService()不会执行onCreate()方法。
也就是说,onCreate()只会在第一次创建service时候调用,多次执行startService()不会重复调用onCreate(),此方法适合完成一些初始化工作。
onStartCommand()
如果多次执行了Context的startService()方法,那么Service的onStartCommand()方法也会相应的多次调用。onStartCommand()方法很重要,我们在该方法中根据传入的Intent参数进行实际的操作,比如会在此处创建一个线程用于下载数据或播放音乐等。
onBind()
Service中的onBind()方法是抽象方法,Service类本身就是抽象类,所以onBind()方法是必须重写的,即使我们用不到。
onDestory()
在销毁的时候会执行Service该方法。
这几个方法都是回调方法,且在主线程中执行,由android操作系统在合适的时机调用。
9.1.2 BindService方式
bindService启动服务特点:
1.bindService启动的服务和调用者之间是典型的client-server模式。调用者是client,service则是server端。service只有一个,但绑定到service上面的client可以有一个或很多个。这里所提到的client指的是组件,比如某个Activity。

&Service服务端
要想让Service支持bindService调用方式,需要做以下事情:
1.在Service的onBind()方法中返回IBinder类型的实例。
2.onBInd()方法返回的IBinder的实例需要能够返回Service实例本身。通常,最简单的方法就是在service中创建binder的内部类,加入类似getService()的方法返回Service,这样绑定的client就可以通过getService()方法获得Service实例了。

&client端要做的事情:
1.创建ServiceConnection类型实例,并重写onServiceConnected()方法和onServiceDisconnected()方法。
2.当执行到onServiceConnected回调时,可通过IBinder实例得到Service实例对象,这样可实现client与Service的连接。
3.onServiceDisconnected回调被执行时,表示client与Service断开连接,在此可以写一些断开连接后需要做的处理。

10、说一下你了解的广播

10.1 静态注册方式
一个广播接收器类
继续需要重写父类的onReceive()方法
在AndroidManifest.xml文件中注册广播
10.2 动态注册方式
一个广播接收器类 —— 实质就是一个继承自BoradCastReceiver的类,只要继承这个类,就
具体接收广播的能力了,但是能接受什么广播由下面的第三条决定。
重写父类的onReceive()方法 —— 接收到广播的时候,就会回调这个方法。因此,广播接收
器的处理逻辑就写在这里
一个 IntentFilter 对象,广播接收器接收什么样的广播,由它的addAction()方法决定。
在代码中注册广播接收器,通过registerReceiver方法。方法接受两个参数,一个是广播接收
器实例,一个是IntentFilter实例。
取消注册广播 ,通过unregisterReceiver() 方法—— 在哪里取消注册无所谓,只要保证取
消注册就OK
10.3 静态注册方式和动态注册方式的区别
动态注册是在Java类中注册,而静态注册是在AndroidManifest.xml中注册。动态注册的广播接收器不是常驻型的,会随着所注册的Activity的结束而结束,如果所在的Activity已经destroy了,那么该广播接收器也就不能再继续接收广播了。注意:在Activity结束前,要取消注册广播接收器,不然会导致内存泄露;静态注册的广播接收器是常驻型的,即使所在的APP被关闭了,也是可以接收到广播的。
当广播为标准广播时:无视优先级,动态注册的优先于静态注册的同优先级的同类广播接收器,动态注册:先注册的优先于后注册的;静态注册:先扫描的优先于后扫描的,当广播为有序广播时:优先级高的先接收、同优先级的广播接收器,动态注册的优先于静态注册的、同优先级的同类广播接收器

11、请说一下内容提供者

ContentProvider为不同的软件之间数据共享,提供统一的接口。也就是说,如果我们想让其他的应用使用我们自己程序内的数据,就可以使用ContentProvider定义一个对外开放的接口,从而使得其他的应用可以使用咱们应用的文件、数据库内存储的信息。当然,自己开发的应用需要给其他应用共享信息的需求可能比较少见,但是在Android系统中,很多系统自带应用,比如联系人信息,图片库,音频库等应用,为了对其他应用暴露数据,所以就使用了ContentProvider机制。所以,我们还是要学习ContentProvider的基本使用,在遇到获取联系人信息,图片库,音频库等需求的时候,才能更好的实现功能。Android系统为了让我们更好的对外暴露数据,提供了统一的接口,所以定义了抽象类ContentProvider,因此,如果我们想对外提供数据,我们需要继承ContentProvider,并且实现下面的这几个方法:
onCreate() 当我们的provider初始化时被调用,我们应该在这个方法里面完成部分初始化操作 query() 查询方法,用于给调用者返回数据 insert() 插入操作,用于让外部应用插入数据到内容提供者中 update() 更新操作,用于更新内容提供者的数据 delete() 用于删除数据 getType 返回内容提供者的MIME Type
上面这些方法,当我们继承自ContentProvider的时候,eclipse会自动的给我们添加,但是这并不代表我们每个方法都需要自定义实现。如果我们只希望给其他应用提供数据,而不允许其他应用修改我们的数据,那么我们只需要实现onCreate(),getType()和query()这三个方法就可以了,其他的三个方法我们可以根据业务需求,实现或者是不实现。
因为一般使用ContentProvider向外部暴露数据库的信息

12、Handler原理

Handler试用方式
Handler使用方式 因发送消息到消息队列的方式不同而不同,共分为2大类:使用 Handler.sendMessage()、使用Handler.post()
Handler中四个重要的类:
处理器 类(Handler)
消息队列 类(MessageQueue)
循环器 类(Looper)
消息 类(Message)
大概原理
创建主线程时,会自动调用ActivityThread的1个静态的main();而main()内则会调用Looper.prepareMainLooper()为主线程生成1个Looper对象,同时也会生成其对应的MessageQueue对象
即 主线程的Looper对象自动生成,不需手动生成;而子线程的Looper对象则需手动通过Looper.prepare()创建
在子线程若不手动创建Looper对象 则无法生成Handler对象
根据Handler的作用(在主线程更新UI),故Handler实例的创建场景 主要在主线程
生成Looper & MessageQueue对象后,则会自动进入消息循环:Looper.loop(),即又是另外一个隐式操作
当创建Handler对象时,则通过 构造方法 自动关联当前线程的Looper对象 & 对应的消息队列对象(MessageQueue),从而 自动绑定了 实现创建Handler对象操作的线程。
消息循环的操作 = 消息出队 + 分发给对应的Handler实例
分发给对应的Handler的过程:根据出队消息的归属者通过dispatchMessage(msg)进行分发,最终回调复写的handleMessage(Message msg),从而实现 消息处理 的操作
特别注意:在进行消息分发时(dispatchMessage(msg)),会进行1次发送方式的判断:
若msg.callback属性不为空,则代表使用了post(Runnable r)发送消息,则直接回调Runnable对象里复写的run()
若msg.callback属性为空,则代表使用了sendMessage(Message msg)发送消息,则回调复写的handleMessage(msg)

13、OKHttp大概工作流程

(1)、当我们通过OkhttpClient创建一个Call,并发起同步或异步请求时;
(2)、okhttp会通过Dispatcher对我们所有的RealCall(Call的具体实现类)进行统一管理,并通过execute()及enqueue()方法对同步或异步请求进行处理;
(3)、execute()及enqueue()这两个方法会最终调用RealCall中的getResponseWithInterceptorChain()方法,从拦截器链中获取返回结果;
(4)、拦截器链中,依次通过RetryAndFollowUpInterceptor(重定向拦截器)、BridgeInterceptor(桥接拦截器)、CacheInterceptor(缓存拦截器)、ConnectInterceptor(连接拦截器)、CallServerInterceptor(网络拦截器)对请求依次处理,与服务的建立连接后,获取返回数据,再经过上述拦截器依次处理后,最后将结果返回给调用方。

14、View和viewgroup区别

View是所有UI组件的基类,而 ViewGroup是容纳这些组件的容器,其本身也是从View派生出来的.简单的说就是:view指某些具体的控件,如Textview,imageview等,ViewGroup是用来盛放这些控件的容器,如LinearLayout和Relativelayout等
这里主要说一下绘制的区别:
UI绘制主要有五个方法:onDraw(),onLayout(),onMeasure(),dispatchDraw(),drawChild()
1.ViewGroup包含这五个方法,而View只包含onDraw(),onLayout(),onMeasure()三个方法,不包含dispatchDraw(),drawChild()。
2.绘制流程:onMeasure(测量)——》onLayout(布局)——》onDraw(绘制)。
3.绘制按照视图树的顺序执行,视图绘制时会先绘制子控件。如果视图的背景可见,视图会在调用onDraw()之前调用drawBackGround()绘制背景。强制重绘,可以使用invalidate();
4.如果发生视图的尺寸变化,则该视图会调用requestLayou(),向父控件请求再次布局。如果发生视图的外观变化,则该视图会调用invalidate(),强制重绘。如果requestLayout()或invalidate()有一个被调用,框架会对视图树进行相关的测量、布局和绘制。
注意:视图树是单线程操作,直接调用其它视图的方法必须要在UI线程里。跨线程的操作必须使用Handler。
5.onLayout():对于View来说,onLayout()只是一个空实现;而对于ViewGroup来说,onLayout()使用了关键字abstract的修饰,要求其子类必须重载该方法,目的就是安排其children在父视图的具体位置。
6.draw过程:drawBackground()绘制背景——》onDraw()对View的内容进行绘制——》dispatchDraw()对当前View的所有子View进行绘制——》onDrawScrollBars()对View的滚动条进行绘制

15、Java 中堆和栈有什么区别?

JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。

栈:在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它
堆:堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。

16、ArrayList和LinkedList有何区别?

ArrayList和LinkedList两者都实现了List接口,但是它们之间有些不同。
(1)ArrayList是由Array所支持的基于一个索引的数据结构,所以它提供对元素的随机访问,复杂度为O(1),但LinkedList存储一系列的节点数据,每个节点都与前一个和下一个节点相连接。所以,尽管有使用索引获取元素的方法,内部实现是从起始点开始遍历,遍历到索引的节点然后返回元素,时间复杂度为O(n),比ArrayList要慢。
(2)与ArrayList相比,在LinkedList中插入、添加和删除一个元素会更快,因为在一个元素被插入到中间的时候,不会涉及改变数组的大小,或更新索引。
(3)LinkedList比ArrayList消耗更多的内存,因为LinkedList中的每个节点存储了前后节点的引用。

17、Java的四种引用及应用场景?

强引用: 通常我们使用new操作符创建一个对象时所返回的引用即为强引用;
软引用: 若一个对象只能通过软引用到达,那么这个对象在内存不足时会被回收,可用于图片缓存中,内存不足时系统会自动回收不再使用的Bitmap;
弱引用: 若一个对象只能通过弱引用到达,那么它就会被回收(即使内存充足),同样可用于图片缓存中,这时候只要Bitmap不再使用就会被回收;
虚引用: 虚引用是Java中最“弱”的引用,通过它甚至无法获取被引用的对象,它存在的唯一作用就是当它指向的对象回收时,本身会被加入到引用队列中,这样我们可以知道它指向的对象何时被销毁。

18、 String, StringBuffer和StringBuilder区别

String:不可变字符串;频繁操作时,每次都需新开辟内存,极易造成内存浪费
StringBuffer:可变字符串、效率低、线程安全;执行速度慢
StringBuilder:可变字符串、效率高、线程不安全;执行速度快

(1)如果要操作少量的数据用 String;
(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder(推荐使用)。

StringBuffer和StringBuilder类的对象能够被多次的修改,并且不产生新的未使用对象。
StringBuilder类在Java5中被提出,它和StringBuffer之间的最大不同在于StringBuilder的方法不是线程安全的(不能同步访问)。

由于StringBuilder相较于StringBuffer有速度优势,所以多数情况下建议使用StringBuilder类。
然而在应用程序要求线程安全的情况下,则必须使用StringBuffer类。

19、请写一下Android中Fragment生命周期,以及各自作用

一、onAttach()
作用:fragment已经关联到activity,这个时候 activity已经传进来了, 获得activity的传递的值 就可以进行 与activity的通信里, 当然也可以使用getActivity(),前提是这个fragment已经和宿主的activity关联,并且没有脱离,有且只有调用一次。
二、onCreate()
作用:系统创建fragment的时候回调他,在他里面实例化一些变量,这些个变量主要是:当你暂停停止的时候你想保持的数据
,只调用一次。
三、onCreateView()
作用: 第一次使用的时候 fragment会在这上面画一个layout出来, 为了可以画控件 要返回一个 布局的view,也可以返回null j 就什么都没有显示。当系统用到fragment的时候 fragment就要快速返回它的view,所以尽量在这里不要做耗时操作,比如从数据库加载大量数据
四、onActivityCreated()
当Activity中的onCreate方法执行完后调用。
五、onStart()
启动Fragement 启动时回调,,此时Fragement可见。
六、onResume()
在activity中的运行是可见的。激活, Fragement 进入前台, 可获取焦点时激活。
七、onPause()
其他的activity获得焦点,这个仍然可见第一次调用的时候,指的是用户离开这个fragment(并不是被销毁)
通常用于用户的提交(可能离开页面后不会再回到这个页面)
八、onStop()
fragment是不可见的,可能出现的情况:activity被stopped了或者 fragment被移除但被,加入到回退栈中,一个stopped的fragment仍然是活着的如果长时间不用也会被移除。
九、onDestroyView()
Fragment中的布局被移除时调用。表示fragemnt销毁相关联的UI布局, 清除所有跟视图相关的资源。然后这个只是移除视图 并没有销毁而且也没有脱离activity
十、onDestroy()
销毁fragment对象。
十一、onDetach()
Fragment和Activity解除关联的时候调用。 脱离activity

20、Activity生命周期

onCreate:与onDestroy配对,表示Activity正在被创建,这是生命周期的第一个方法。在这个方法中可以做一些初始化的工作(加载布局资源、初始化Activity所需要的数据等),耗时的工作在异步线程上完成。

onRestart:表示Activity正在重新启动。一般情况下,在当前Activity从不可见重新变为可见的状态时onRestart就会被调用。这种情形一般是由于用户的行为所导致的,比如用户按下Home键切换到桌面或者打开了一个新的Activity(这时当前Activity会暂停,也就是onPause和onStop被执行),接着用户有回到了这个Activity,就会出现这种情况。

onStart:与onStop配对,表示Activity正在被启动,并且即将开始。但是这个时候要注意它与onResume的区别。两者都表示Activity可见,但是onStart时Activity还正在加载其他内容,正在向我们展示,用户还无法看到,即无法交互。

onResume:与onPause配对,表示Activity已经创建完成,并且可以开始活动了,这个时候用户已经可以看到界面了,并且即将与用户交互(完成该周期之后便可以响应用户的交互事件了)。

onPause:与onResume配对,表示Activity正在暂停,正常情况下,onStop接着就会被调用。在特殊情况下,如果这个时候用户快速地再回到当前的Activity,那么onResume会被调用(极端情况)。一般来说,在这个生命周期状态下,可以做一些存储数据、停止动画的工作,但是不能太耗时,如果是由于启动新的Activity而唤醒的该状态,那会影响到新Activity的显示,原因是onPause必须执行完,新的Activity的onResume才会执行。

onStop:与onStart配对,表示Activity即将停止,可以做一些稍微重量级的回收工作,同样也不能太耗时(可以比onPause稍微好一点)。

onDestroy:与onCreate配对,表示Activity即将被销毁,这是Activity生命周期的最后一个回调,我们可以做一些回收工作和最终的资源释放(如Service、BroadReceiver、Map等)。

21、EventBus

EventBus的优势
· 简化了组件之间的通信
1、事件发送者和接收者的解耦
2、很好地工作在Activities, Fragments,后台线程中
3、避免复杂且容易出错的依赖关系和生命周期问题
· 使代码更简单
· 很快(EventBus 3.x 版本性能非常好,官方自称是同类框架中最快的)
· 很小(~50 K)在实践中被一亿多安装的应用程序所证明
· 具有高级特性,如线程分发、订阅者优先级等
一、Eventbus的创建
Eventbus的构造方法是由public修饰的,this(DEFAULT_BUILDER)对eventbus进行初始化。在构造方法中创建了3个关键Post它们负责线程间的调度,分别是mainThreadPoster、backgroundPoster、asyncPoster 。但是最终还是通过构建者模式Builder内部类的形式创建的。
二、subscribe注解
@Retention(RetentionPolicy.RUNTIME) 在运行是有效 在运行时保留subscribe注解。
@Target({ElementType.METHOD}) 用来描述方法。
ThreadMode threadMode() default ThreadMode.POSTING; 返回线程的模式。
boolean sticky()判断是否为粘性事件 :事件消费者在事件发布之后才注册的也能接收到该事件的特殊类型。 androideventbus会存储所有的sticky事件。
int priority() default 0 设置优先级
三、eventbus的注册
register(this);
通过反射创建一个subscribe的class的对象,通过subscriberMethodFinder的findSubscriberMethods方法获取到List的集合;
在同步代码块中对subscriberMethods集合遍历,调用subscribe(subscriber, subscriberMethod),方法对每一个方法进行订阅.
在subscribe()方法中判断if (eventType.isAssignableFrom(candidateEventType)) {事件是否有继承关系如果有就会调用最核心的分发事件的方法checkPostStickyEventToSubscription();
1、首先判断是否有注册过该事件.2、按照优先级的加入到subscriptionsByEventtype的value的集合中.3、然后再添加到typeBySubscriber的values的list中.4、分发事件:checkPostStickyEventToSubscription()。
而checkPostStickyEventToSubscription()会调用postToSubscription()来完成实际的分发;
然后判断isMainThread()是否在主线程当中:
是POSTING的话直接调用invokeSubscriber来完成线程的调用 此方法通过反射来完成的;
是MAIN的话判断如果在Ui线程中通过invokeSubscriber来完成线程的调用如果不是则调用mainThreadPoster.HandlerPoster实现了Poster接口把enqueue(subscription, event);放入消息队列中进行操作;
是BACKGROUND的话,继续判断如果在Ui线程中通过backgroundPoster()进入队列,如果不在Ui线程中调invokeSubscriber();
4不管在不在主线程中都会调用asyncPoster加入到队列中
四、Post发送线程
在post方法中首先通过currentPostingThreadState.get();获取到一个PostingThreadState类,这个类就是发送事件的一个线程状态的一个封装类;
这里要说明currentPostingThreadState就是ThreadLocal 它是线程独有的它不会和其他线程共享当前线程的数据;
然后判断postingState.isPosting 是否为true,为true的话把发送事件的标志位isPosting设置为true,表示该事件在发送,其他事件等一会再运行;
try {
while (!eventQueue.isEmpty()) {
不为null时发送事件
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
最后标志位全部设置为false
postingState.isPosting = false;
postingState.isMainThread = false;
}
eventbus中ThreadMode的四种模式(了解)
(1)POSTING:这种模式就是eventBus默认的模式,我们在使用的时候不需要再订阅者的方法的注解后面加任何东西(选择模式),但是这种只能在同一个线程中接收,也就是说,如果是在主线程中发布消息就只能在主线程中接收消息,如果是在子线程中,那么也只能在相同的子线程中去接收消息。如果非要声明POSTING的话,写法如下:
@Subscribe(threadMode = ThreadMode.POSTING)
public void showMsgFromSecondActivity(MessagePojo msg){
Log.i(“test”, ((String) msg.obj));
}
(2)MAIN:这种模式保证了订阅者指定的那个接收方法肯定要主线程中执行,可以放心的在里面执行更新UI操作。无论发布者是在主线程中还是在那一条子线程中发布消息,这边接收的都在主线程中。写法如下

@Subscribe(threadMode = ThreadMode.MAIN)
public void showMsgFromSecondActivity(MessagePojo msg){
Log.i(“test”, ((String) msg.obj));
}

(3)BACKGROUND:这种模式无论发布者是在主线程或者是那一条子线程中发布消息,接收的肯定是在子线程中,并且是这样理解:如果是在主线程中发布消息,那么就会随机开辟一条子线程来接收消息。如果是在子线程中发布消息,那么就会在相同的子线程来接收消息。写法如下:
@Subscribe(threadMode = ThreadMode.BACKGROUDN)
public void showMsgFromSecondActivity(MessagePojo msg){
Log.i(“test”, ((String) msg.obj));
}
(4)ASYNC:这种模式是无论你在那个线程中发布消息都会在不同的线程中接受消息。如果你在主线程中发布消息,就会随机的开辟一条子线程来接收消息;如果是在子线程中发布消息,就会开辟一条不同的子线程来接收消息。
写法如下:
@Subscribe(threadMode = ThreadMode.ASYNC)
public void showMsgFromSecondActivity(MessagePojo msg){
Log.i(“test”, ((String) msg.obj));
}

22、标注:序列化

什么叫序列化:
序列化: 把对象写入到磁盘或其他介质中,这个过程叫序列化。
反序列化:把已经存在在磁盘或其他介质中的对象,反序列化到内存当中,以便后续频繁的操作
必要条件:一个对象要实现序列化操作,就必须实现Serializable接口或Parcelable接口,其中Serializable接口是在Java中的序列化抽象类,而Parceable接口则是android特有的序列化接口。

为什么要序列化:java对象序列化后可以很方便的存储或者在网络中传输

具体过程:
序列化操作时,系统会把当前类的serialVersionUID写到序列化的文件当中,而当反序列化时系统又会检测文件当中的serialVersionUID,判断是否和当前类的serialVersionUID一致,如果一致就说明序列化的版本和当前类的序列化版本是一样的,那么就可以反序列化反之就反序列化失败。

Serializable和Parcelable
Serializable是java提供的一个序列化接口,是一个空接口,专门为对象提供标准序列化和反序列化操作,实现类的序列化比较简单,只要在类的声明中实现Serializable接口即可。
Serializable序列化时会生成一个long整型,用来辅助序列化和反序列化过程。原则上序列化后的对象中serialVersionUID只有和当前类的serialVersionUID相同才能够正常被反序列化
两者的设计初衷:
(1)Serializable的设计初衷是为了序列化对象到本地文件、数据库、网络流、RMI以便数据传输,当然这种传输可以是程序内的也可以是两个程序间的。
(2)Android的Parcelable的设计初衷是由于Serializable效率过低,消耗大,而android中数据传递主要是在内存环境中(内存属于android中的稀有资源),因此Parcelable的出现是为了满足数据在内存中低开销而且高效地传递问题。
两者的区别:
实现上的差异:
Serializable实现只需要通过一个Serializable接口就可以实现给这个对象添加一个serialVersionUID,系统会自动将其序列化
Parcelable实现不仅需要实现Parcelable接口还需要在类中添加一个静态成员变量CREATOR,这个变量需要实现Parceable.Creator接口,并实现读写的抽象方法。
效率上的对比:
Serializable使用IO读写存储在硬盘上。在持久化操作方面较方便,所以序列化到存储设备中一般使用Serializable,Parcelable也行但是操作麻烦,并且为了防止Android不同版本之间的差异有可能导致Parcelable之间使用不同的情况,因此对象序列化写到存储设备或者网络传输方面尽量用Serializable.
(2) Parcelable直接在内存中读写,性能好特别是在内存开销方面,所以Android应用在内存间传输数据一般用Parcelable.如activity间传输数据和AIDL.

23、Android与js交互

Android与js交互,有两种情况,一种是我们Android去调用js的方法,一种是js调用我们Android的方法。而相互调用的桥梁就是我们的WebView了。首先我们需要先设置webview支持js:webSettings.setJavaScriptEnabled(true);

Android调用js方法有两种方式:
*一通过WebView的loadUrl()加载js方法。mWebView.loadUrl(“javascript:callJS()”);
方法里面写的是固定格式,后面的calljs是对应的JS中的方法名字。 注意调用的JS方法名要对应上。
*二通过WebView的evaluateJavascript()。这个方法比第一种方法效率更高、使用更简洁。因为这个方法的执行不会使页面刷新,而上一种方法(loadUrl )的执行则会。但是这个方式是Android 4.4 后才可使用。
一般的使用的时候,两种方法混合使用,即Android 4.4以下使用第一种方法,Android 4.4以上方法用第二种方式
两种方式的对比:

Js调用Android的方式:
Js调用android有三种方式
一是通过 WebView的addJavascriptInterface()进行对象映射。先定义一个与JS对象映射关系的Android类,然后在类中的方法上添加而且必须加入@JavascriptInterface注解。
然后通过webview的方法mWebView.addJavascriptInterface(new AndroidtoJs(), “test”);//AndroidtoJS类对象映射到js的对象。这个方式使用起来比较简单,但是会有内存泄漏的问题。
二是通过 WebViewClient 的方法shouldOverrideUrlLoading ()回调拦截 url。
Android通过 WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url
解析该 url 的协议,如果检测到是预先约定好的协议,就调用相应方法。这里的协议就是相应的约定好的一种格式。这种方式就是不会存在第一种方式的内存泄漏的问题。但是就是获取返回值比较麻烦。
三是通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息Android通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调分别拦截JS对话框
(即上述三个方法),得到他们的消息内容,然后解析即可。

24、进程间通信有哪些方式

1.Bundle 只能传输Bundle支持的数据类型,适用于四大组件间的进程间通信。
文件共享 不适用高并发场景,并且无法做到进程间即时通信,适用于无关发的情况下,交换简单的数据,对实
时性要求不高的场景。
2.AIDL 功能强大,支持一对多实时并发通信,使用稍复杂,需要处理好线程间的关系,一对多通信且有RPC需求
3.Messenger 功能一般,支持一对多串行通信,支持实时通信,不能很好地处理高并发的情形,不支持RPC,
由于数据通过Message传输,因此只能传输Bundle支持的数据类型,低并发的一对多实时通信,无RPC需求,
或者无需要返回结果的RPC需求
4.ContentProvider 支持一对多的实时并发通信,在数据源共享方面功能强大,可通过Call方法扩展其它操
作,可以理解为受约束的AIDL,主要提供对数据源的CRUD操作.
5.BroadcastReceiver 操作简单,对持一对多实时通信,只支持数据单向传递,效率低且安全性不高,
一对多的低频率单向通信
6.Socket 功能强大,可通过网络传输字节流,支持一对多实时并发通信,实现细节步骤稍繁琐,不支持直接的
RPC,网络间的数据交换
由于不同的进程拥有不同的数据空间,所以无论是应用内还是应用间,均无法通过共享内存来实现进程间通信。

应用内使用多进程可能导致哪些问题?
当一个APP启用了多进程后,系统会为不同的进程分配不同的内存空间,因此所有需要通过内存共享的行为都会失败。另外,还会导致以下几个问题:
进程:Application会被多次创建,因为系统会为每一个进程分配独立的内存空间。
线程:线程同步失效,因为不同进程中的线程同步锁不是同一个对象。
内存:单例模式和静态变量失效,因为不同进程间的内存空间不同。
存储:SharedPreferences可靠性下降,因为系统对SharedPreferences有一定的缓存策略,多个进程同时读写可能会造成数据丢失。

25、面向对象编程的几大特性及其含义?

抽象:对现实世界的事物进行概括,抽象为在计算机虚拟世界中有意义的实体
封装:将某事物的属性和行为包装到对象中,构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,并且尽可
能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系
继承:子类继承父类,不仅可以有父类原有的方法和属性,也可以增加自己的或者重写父类的方法及属性
多态:允许不同类的对象对同一消息做出各自的响应

26遇见过哪些运行时异常?异常处理机制知道哪些?

(1) Throwable继承层次结构,可见分成两大类Error和Exception:
Error(错误):指程序无法恢复的异常情况,表示运行应用程序中较严重的问题;发生于虚拟机自身、或者在虚拟机试图执
行应用时,如Virtual MachineError(Java虚拟机运行错误)、NoClassDefFoundError(类定义错误);属于不可
查异常,即不强制程序员必须处理,即使不处理也不会出现语法错误。
Exception(异常):指程序有可能恢复的异常情况,表示程序本身可以处理的异常。又分两大类:
RuntimeException(运行时异常):由程序自身的问题导致产生的异常;如NullPointerException(空指针异常)、
IndexOutOfBoundsException(下标越界异常);属于不可查异常。
非运行时异常:由程序外部的问题引起的异常;除了RuntimeException以外的异常,如FileNotFoundException(文
件不存在异常);属于可查异常,即强制程序员必须进行处理,如果不进行处理则会出现语法错误。

(2)常见的异常处理机制有:
捕捉异常:由系统自动抛出异常,即try捕获异常->catch处理异常->finally 最终处理
抛出异常:在方法中将异常对象显性地抛出,之后异常会沿着调用层次向上抛出,交由调用它的方法来处理。配合throws声
明抛出的异常和throw抛出异常
自定义异常:继承Execption类或其子类

27、Java中引用有几种类型?在Android中常用于什么情景?

强引用(StrongReference):具有强引用的对象不会被GC;即便内存空间不足,JVM宁愿抛出OutOfMemoryError使程
序异常终止,也不会随意回收具有强引用的对象。
软引用(SoftReference):只具有软引用的对象,会在内存空间不足的时候被GC;软引用常用来实现内存敏感的高速缓
存。
弱引用(WeakReference):只被弱引用关联的对象,无论当前内存是否足够都会被GC;强度比软引用更弱,常用于描述
非必需对象;常用于解决内存泄漏的问题
虚引用(PhantomReference):仅持有虚引用的对象,在任何时候都可能被GC;常用于跟踪对象被GC回收的活动;必须
和引用队列 (ReferenceQueue)联合使用,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对
象的内存之前,把这个虚引用加入到与之关联的引用队列中。

28、Okhttp中的拦截器以及作用
	创建响应数据,根据响应码做处理
	添加完数据后返回响应体到上一层

#总结

RetryAndFollowUpInterceptor:负责请求的重试和重定向
BridgeInterceptor:给请求添加对应的 header 信息,处理响应结果的 header 信息
CacheInterceptor:根据当前获取的状态选择 网络请求 、读取缓存、更新缓存。
ConnectInterceptor:建立 http 连接。
CallServerInterceptor:读写网络数据。

29、Fragment与Activity通信和Fragment与Fragment之间的相互通信

##Fragment与Activity

####Activity到Fragment

在创建Fragment的时候调用这个Fragment的setArguments()传入一个Bundle对象传入数据(不推荐传非基本类型的)
或在Fragment的构造中添加需要参数的构造
还可以在Fragment中直接创建一个方法 在创建Fragment时调用方法传入数据
(如果传入的数据需要逻辑处理最好不要用,这个方法在调用时Fragment的view还没创建完成,只能进行传值)

####Fragment到Activity

在Fragment调用getActivity()返回的activity就是存有在这个Fragment的Activity对象,可以强转为这个Activity的对象然后调用方法直接传值
或在Fragment中创建一个接口 然后由创建这个Fragment的Activity实现这个接口就可以让Fragment传值到Activity了

##Fragment与Fragment

用getActivity()获取到当前依附的Activity然后强转后调用Activity的方法获取到想要的Fragment然后传值,setArguments()或直接调用方法
或者以FragmentManeage调用findFragmentById("ID"),或者ByTag()也可以前提是这个Fragment有Tag,
或者用FragmentManeage获取到Fragment的集合getFragments(),然后手动遍历判断集合的Fragment是否是需要的Fragmeng然后setArguments()或直接调用方法传值(不推荐)

##通用方法
可以直接使用广播传值 或者 使用EventBus传值

30、ANR如何产生,ANR如何避免

Android系统中,ActivityManagerService(简称AMS)和WindowManagerService(简称WMS)会检测App的响应时间,如果App在特定时间无法相应屏幕触摸或键盘输入时间,或者特定事件没有处理完毕,就会出现ANR。
以下四个条件都可以造成ANR发生:
• InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件
• BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒。
• Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕。
• ContentProvider Timeout :ContentProvider的publish在10s内没进行完。
基本都是主线程被阻塞,所以说尽量避免在主线程(UI线程)中作耗时操作。
使用子线程来处理耗时操作或阻塞任务。尽量避免在主线程query provider、不要滥用SharePreferenceS。

31、面向对象编程的四大特性及其含义?

技术点:面向对象编程特点
思路:分条简述每个特性的含义
参考回答:
抽象:对现实世界的事物进行概括,抽象为在计算机虚拟世界中有意义的实体
封装:将某事物的属性和行为包装到对象中,构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,并且尽可
能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系
继承:子类继承父类,不仅可以有父类原有的方法和属性,也可以增加自己的或者重写父类的方法及属性
多态:允许不同类的对象对同一消息做出各自的响应

32、String、StringBuffffer和StringBuilder的区别?

技术点:String
参考回答:
String是字符串常量,而StringBuffer、StringBuilder都是字符串变量,即String对象一创建后不可更改,而后两
者的对象是可更改的:
StringBuffer是线程安全的,而StringBuilder是非线程安全的,这是由于StringBuffer对方法加了同步锁或者对调
用的方法加了同步锁
String更适用于少量的字符串操作的情况,StringBuilder适用于单线程下在字符缓冲区进行大量操作的情况,
StringBuffer适用于多线程下在字符缓冲区进行大量操作的情况

33、String a="“和String a=new String(”")的的关系和异同?

技术点:String
参考回答:
通过String a="“直接赋值的方式得到的是一个字符串常量,存在于常量池;注意,相同内容的字符串在常量池中只有一
个,即如果池已包含内容相等的字符串会返回池中的字符串,反之会将该字符串放入池中
通过new String(”")创建的字符串不是常量是实例对象,会在堆内存开辟空间并存放数据,且每个实例对象都有自己的地
址空间
引申:对于用String a="“和String a=new String(”")两种方式定义的字符串,判断使用equals()、"=="比较结果
是什么

34、Object的equal()和==的区别?

技术点:equal()、==
参考回答:
equals():是Object的公有方法,具体含义取决于如何重写,比如String的equals()比较的是两个字符串的内容是否相

"" :对于基本数据类型来说,比较的是两个变量值是够是否相等,对于引用类型来说,比较的是两个对象的内存地址是
否相同
引申:对于用String a="“和String a=new String(”")两种方式定义的字符串,判断使用equals()、"
"比较结果
是什么

35、装箱、拆箱什么含义?

技术点:装箱、拆箱
参考回答:装箱就是自动将基本数据类型转换为包装器类型,拆箱就是自动将包装器类型转换为基本数据类型

36、int和Integer的区别?

技术点:基本数据类型、引用类型
参考回答:
Integer是int的包装类,int则是java的一种基本数据类型
Integer变量必须实例化后才能使用,而int变量不需要
Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
Integer的默认值是null,int的默认值是0

37、什么是反射,有什么作用和应用?

技术点:反射
思路:简述反射的定义、功能和应用,详见Java基础之泛型&反射
参考回答:
含义:在运行状态中,对于任意一个类都能知道它的所有属性和方法,对于任何一个对象都能够调用它的任何一个方法和属
性。
功能:动态性,体现在:在运行时判断任意一个类所具有的属性和方法; 在运行时判断任意一个对象所属的类;在运行时构
造任意一个类的对象;在运行时调用任意一个对象的方法;生成动态代理
应用:反射&泛型

38、什么是内部类?有什么作用?静态内部类和非静态内部类的区别?

技术点:内部类
思路:
参考回答:内部类就是定义在另外一个类里面的类。它隐藏在外部类中,封装性更强,不允许除外部类外的其他类访问它;
但它可直接访问外部类的成员。静态内部类和非静态内部类的区别有:
静态内部类是指被声明为static的内部类,可不依赖外部类实例化;而非静态内部类需要通过生成外部类来间接生成。
静态内部类只能访问外部类的静态成员变量和静态方法,而非静态内部类由于持有对外部类的引用,可以访问外部类的所用
成员

39、fifinal、fifinally、fifinalize()分别表示什么含义

技术点:final、finally、finalize()
参考回答:
final关键字表示不可更改,具体体现在:
final修饰的变量必须要初始化,且赋初值后不能再重新赋值
final修饰的方法不能被子类重写
final修饰的类不能被继承
finally:和try、catch成套使用进行异常处理,无论是否捕获或处理异常,finally块里的语句都会被执行,在以下4种
特殊情况下,finally块才不会被执行:
在finally语句块中发生了异常
在前面的代码中用了System.exit()退出程序
程序所在的线程死亡
关闭CPU
finalize():是Object中的方法,当垃圾回收器将回收对象从内存中清除出去之前会调用finalize(),但此时并不代表
该回收对象一定会“死亡”,还有机会“逃脱

39、重写和重载的区别?

技术点:重写、重载
参考回答:重写表示子类重写父类的方法;重载表示有多个同名函数同时存在,区别在于有不同的参数个数或类型
引申:谈谈动态分派和静态分派

40、抽象类和接口的异同?

技术点:抽象类、接口
参考回答:
使用上的区别:一个类只能继承一个抽象类却可以实现多个接口
设计上的区别:接口是对行为的抽象,无需有子类的前提,是自上而下的设计理念;抽象类是对类的抽象,建立于相似子类
之上,是自下而上的设计理念

41、为什么匿名内部类中使用局部变量要用fifinal修饰?

技术点:匿名内部类
参考回答:一方面,由于方法中的局部变量的生命周期很短,一旦方法结束变量就要被销毁,为了保证在内部类中能找到外
部局部变量,通过final关键字可得到一个外部变量的引用;另一方面,通过final关键字也不会在内部类去做修改该变量
的值,保护了数据的一致性。

42、Object有哪些公有方法?

技术点:Object
思路:列举常见的几个公有方法
参考回答:
equals(): 和==作用相似
hashCode():用于哈希查找,重写了equals()一般都要重写该方法
getClass(): 获取Class对象
wait():让当前线程进入等待状态,并释放它所持有的锁
notify()&notifyAll(): 唤醒一个(所有)正处于等待状态的线程
toString():转换成字符串

43、Java集合框架中有哪些类?都有什么特点

技术点:集合框架
思路:分条解释每种类的特点
参考回答:可将Java集合框架大致可分为Set、List、Queue 和Map四种体系
Set:代表无序、不可重复的集合,常见的类如HashSet、TreeSet
List:代表有序、可重复的集合,常见的类如动态数组ArrayList、双向链表LinkedList、可变数组Vector
Map:代表具有映射关系的集合,常见的类如HashMap、LinkedHashMap、TreeMap
Queue:代表一种队列集合


作者:名字是真的不好起


阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-移动开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯