Android岗的面试高频题(待补充)

Android开发岗高频题

1.java中的作用域

  • public:可以被所有其他类所访问
  • private:只能被自己访问和修改
  • protected:自身、子类及同一个包中类可以访问
  • default:同一包中的类可以访问,声明时没有加修饰符,认为是friendly。

2.hashcode(),equals,==的区别

  • 如果两个对象equals相等,Java运行时环境会认为他们的hashcode一定相等。
  • 如果两个对象equals不相等,他们的hashcode有可能相等。
  • 如果两个对象hashcode相等,他们equals不一定相等。
  • 如果两个对象hashcode不相等,他们equals一定不相等。
  • ==等号如果比基本数据类型的话(int long float …)比的就是值
  • ==等号如果比的是对象的话,比的是对象里的地址是否相等。
  • equals主要是比对两个字符串/字符是否相等。

3.HashMap和HashTable的区别

HashMap是线程不安全的:意思是在多个线程中使用HashMap时,例如线程A(客户)和线程B(客户)去共享资源(窗口)买票,还剩1张票时,线程不安全的话,他们两个人就会同时买到这一张票。

HashTable是线程安全的:意思在多个线程中使用HashTable时,买票为例子:如果A先买票,那么就是A有票,B就无法买票了。主要看谁网速快,谁先买到。使线程安全的原因是在方法中加了synchronized这个关键字,使得线程必须同步执行,即线程A执行完了过后,线程B才能执行。

4.ArrayList和LinkedList的区别

ArrayList:底层基于数组形式,数组的特点,是占用连续的内存空间 且内部实现了快速随机访问,宏观上所以查找很快,插入和删除数据很慢。为什么会出现这种情况?答:因为数组查询数据快是数组的特点,内存是连续的,插入和删除慢是因为,在数组中间插入一个值,那么后面的所有数组数据就要往后移,开销比较大,速度就比较慢,删除也是同理。

LinkedList:底层基于链表形式,链表形式即(一个节点,包含了节点数据和指向下一个节点的指针),宏观上插入和删除比较快,查询比较慢。为什么会出现这种情况?答:插入和删除快,因为链表的特点,删除某个数据节点,去删除节点的时候会把链表分为两半,判断删除的节点在前半段还是后半段,如果是在前半段,则从前半段的末尾节点去从后往前遍历找到要删除的节点,如果是后半段,则从后半段的链表头部,从前往后遍历查找要删除的节点。而不需要去全部遍历,即找到前一个指向删除节点的指针域就可以了。而查询慢是因为链表要程序找指针域,一个个去遍历下来,开销大。

特殊情况:

ArrayList在数组后面插入一个数,则不需要改动数组的位置,因为在后面插入数,前面的数不需要变化,这样的情况跟linkedList得插入差不多。

LinkedList去查询一个数的话,如果那个数(节点)正好在中间,则跟ArrayList查询差不多快,因为LinkedList分为了前半段和后半段去查询数(节点)。

ArrayList扩容机制:当容量满了的时候会重新创建一个比之前的要大1.5倍的ArrayList,再把之前的ArrayList重新按顺序放进1.5倍打的ArrayList中。

5.HashMap内部原理

HashMap底层是以数组+链表形式去存储数据的,即每个数组元素都是一个链表,称为 桶。HashMap存储键值对,实现快速存取数据;允许null键/值

put()操作:首先会计算key的hashcode值,通过这个值和数组的长度进行模运算,得到数组中的元素(桶)就是put要存储的位置,如果key相同,则替换掉之前的value值。

get()操作:首先会计算key的hashcode值,通过这个值和数组的长度进行模运算,得到数组中的元素(桶),再对它的key进行做hashcode计算,如果hashcode值相同(产生碰撞),则比对它们的equals是否相同,如果相同则找到了要得到的位置取出即可。如果没发生碰撞,则不需要进行equals。

HashMap扩容机制:,阈值=loadfactor*current capacity,load factor默认0.75。HashMap内部的参数就是loadfactor和current capacity,第一个参数默认为0.75,(75%),第二个参数为HashMap的大小。如果HashMap的容量占用到了75%时,会重新扩容从两倍容量。

6.Android中的Activity生命周期

onCreate()

当活动创建时执行

onStart()

当活动可见时执行,就是进入前台时

onResme()

这个方法在活动准备好和用户进行交互的时候,并且此时的活动一定位于返回栈的栈顶,并且处于运行状态时执行。

onPause()

当活动部分可见时执行,声明:dialog提示窗并不会执行此方法,网上那些都是愣头青,瞎转载没测试的。为什么说当活动部分可见时执行呢,如果是activity设置为dialog形式的时候才会调用。

添加 android:theme="@android:style/Theme.Dialog" 。将Activity修改为Dialog样式。 即可

当 当前活动全部不可见时也会调用。

onStop()

当活动不可见时调用

onDestory()

当活动销毁时调用,比如按了手机自带返回键,或者设置了Finnish()

补充Intent【A跳转到B】的生命周期

A:代表A的生命周期;

B:代表B的生命周期;

onCreate(A)→onStart(A)→onResme(A)→onPause(A)→onCreate(B)→onStart(B)→onResme(B)→onStop(A)

当又返回A时

onPause(B)→onRestart(A)→onStart(A)→onResme(A)→onStop(B)→onDestroy(B)

Dialog和AlertDialog并不会影响到Activity的生命周期

因为dialog依附于 activity, 并没有被遮挡。

7.Intent传递数据和Bundle传递数据时的问题

Intent传递的数据类型必须是八种基本数据类型(int ,float …)和必须实现序列化的类。

序列化(Servalable,Parceable)两种序列化。

序列化是什么:我们的对象并不只是存在内存中,还需要传输网络,或者保存起来下次再加载出来用,所以需要Java序列化技术。Java序列化技术正是将对象转变成一串由二进制字节组成的数组,可以通过将二进制数据保存到磁盘或者传输网络,磁盘或者网络接收者可以在对象的属类的模板上来反序列化类的对象,达到对象持久化的目的。

两种序列化的差别:第一种是java自带的序列化,用于把数据序列化从文件的形式保存到磁盘,但是会产生大量的临时变量,导致很卡(GC(垃圾回收)发生频繁),不适用内存中的传输数据。

第二种是Android自带的序列化,不能把数据序列化到磁盘上,序列化从二进制形式在内存上进行数据传输。

8.Android中的四大组件

  • 活动(Activity)
  • 广播(BoderCast Recevier)
    分为有序广播和无序广播,也分为粘性广播和标准广播,静态注册广播和动态广播。有序和无序的区别是设置了广播的优先级,优先级越高,就越先执行广播;粘性和标准的区别就是:粘性广播不考虑其他APP发送广播给我时注册了没有,一旦我注册了广播就会收到,没注册时就等待接收,标准广播的话就不会像这样。静态广播的话是需要在AndroidManifest.xml进行注册的,程序没启动时,广播也在运行。动态广播的话,不用在AndroidManifest.xml进行注册,通过代码形式注册,程序启动时,广播才会启动。
  • 服务(Service)
    后台服务,用于客户端和服务端进行交互。有两种启动方式
    1.onBindService
    生命周期:onCreate,onStart,onBind,onStop,onDestory。onCreate创建后不再执行,当再次执行广播时只会从onStart开始还在。onBind返回了一个bind对象给客户端。
    2.onStartService
    生命周期:onCreate,onStart,onStartCommnd,onStop,onDestory。同上,onCreate创建后不再执行。
    3.IntentService
    它是service的一个子类,通过调用onHandleIntent的方式开启线程任务,每个任务是线程同步执行的,即一个线程执行结束再执行另一个线程。一个个来。什么时候会用到这个子类,比如(一个大任务,可以分为很多子任务时,例如应用商店,下载很多APP时,可以考虑这种,不过一般应用商店下载的APP都是异步下载,不会排队下载)
  • 内容提供者(content provider)
    跨应用访问数据,直接操控sqlite数据库等。比如直接访问手机里的联系人等。

9.Android中的五大布局

  1. FrameLayout(帧布局,框架布局)
    所有的控件都会依次在屏幕左上角显示,会重叠。FrameLayout是最简单的一个布局对象。它被定制为你屏幕上的一个空白备用区域,之后你可以在其中填充一个单一对象 — 比如,一张你要发布的图片。所有的子元素将会固定在屏幕的左上角;你不能为FrameLayout中的一个子元素指定一个位置。后一个子元素将会直接在前一个子元素之上进行覆盖填充,把它们部份或全部挡住(除非后一个子元素是透明的)。这个布局可以看成是墙脚堆东西,有一个四方的矩形的左上角墙脚,我们放了第一个东西,要再放一个,那就在放在原来放的位置的上面,这样依次的放,会盖住原来的东西。这个布局比较简单,也只能放一点比较简单的东西。
  2. LinearLayout(线性布局)
    线性布局是所有布局中最常用的类之一,也是RadioGroup, TabWidget, TableLayout, TableRow, ZoomControls类的父类。LinearLayout可以让它的子元素垂直(android:orientation=”vertical”)或水平(android:rientation=”horizontal”)的方式排成一行(不设置方向的时候默认按照垂直方向排列)。当垂直布局时,每一行就只有一个元素,多个元素依次垂直往下;水平布局时,只有一行,每一个元素依次向右排列。
    linearLayout中有一个重要的属性 android:layout_weight=”1”,这个weight在垂直布局时,代表行距;水平的时候代表列宽;weight值越大就越大。
  3. AbsoluteLayout(绝对布局)
    由于AbsoluteLayout已经不在支持,所以我们这里也不再介绍。在实际开发中也强烈建议不要使用AbsoluteLayout布局方式,因为不同的手机的分辨率是不同的,不同有固定的像素去摆放组件的位置。同时,每一种布局也有其局限性,所以在实际开发中,我们常常同时嵌套使用一种或多种布局方式,以呈现出更美观的用户界面。
  4. RelativeLayout(相对布局)
    RelativeLayout 允许子元素指定他们相对于其它元素或父元素的位置(通过ID 指定)。因此,你可以以右对齐,或上下,或置于屏幕中央的形式来排列两个元素。元素按顺序排列,因此如果第一个元素在屏幕的中央,那么相对于这个元素的其它元素将以屏幕中央的相对位置来排列。如果使用XML 来指定这个 layout ,在你定义它之前,被关联的元素必须定义。
  5. TableLayout(表格布局)
    表格布局,将子元素的位置分配到行或列中。一个TableLayout 由许多的TableRow (行)组成.TableLayout 容器不会显示row 、cloumns 或cell 的边框线。每个 row 拥有0个或多个的cell ;每个cell 拥有一个View 对象。表格由列和行组成许多的单元格。表格允许单元格为空。单元格不能跨列,这与HTML 中的不一样。

10.Android中的动画有哪几种

1.补间动画/视图动画

没有改变实际的view宽高大小,只是改变了视图显示位置。那么在动画移动过程中,点击事件就无效了。因为实际的view没有跟着动

2.帧动画

一帧帧的动画,记得图片不要太大,会很容易导致OOM,内存溢出。

3.属性动画

改变了view的实际位置,可以实现点击事件。

动画的一些属性

    名称       	    原理     	对应的Animation的子类    

平移动画(Translate) 移动视图的位置 TranslateAnimation类
缩放动画(Scale) 放大/缩小 视图的大小 ScaleAnimation类
旋转动画(Rotate) 旋转视图的角度 RotateAnimation类
透明度动画(Alpha) 改变视图的透明度 AlphaAnimation类

11.Android中四种启动模式

1.standard(默认模式)

standard模式下,会不断地新建activity实例,都放入同一个堆栈中

2.singleTop

如果当前实例在当前的task的栈顶,则直接复用,如果当前实例不再栈顶,则新建实例。

3.singleTask

设置了singleTask的页面,只要是task中有这个实例,就会一直复用,而且每次复用这个已存在的实例,都会清空上面的其他实例,将自己直接提升到栈顶位置,显示自己

4.singleInstance

设置了singleInstance的页面,初始时都是新建一个task栈给这个页面,然后后面一直复用这个栈内的页面。注意,只有这种模式会新建一个栈给初始化的页面。最后返回的规律是,先把本页面所在的栈都出完,然后再弹出下一个栈的每个页面。

12.handler跨线程机制

大概的说一下。

分为4个角色:

handler:跨线程数据接受者。

message:跨线程传输消息的消息主体。

message enqueue:消息队列,以链表的形式存储着message。message分为延迟消息和非延迟消息。延迟越大,就放在消息队列的越后面。

Loopr:消息队列(message enqueue)的管理者,控制着消息队列中的消息的存入和放出。线程通过Looper建立自己的消息循环,Looper负责从MessageQueue中取出消息,并且分发到消息指定目标Handler对象。

大概流程

子线程发送数据给主线程时,在子线程中调用,handler.sendMessage(message)(延迟默认为0ms) 发送消息时,会一步步调用走到

handler.sendMessageDelayd(message)中,里面实现了当前时间+消息的延迟时间,接着调用handler.sendMessageAttime(message),确定了消息的延迟发送时间,接着调用message enqueue,准备把message加入消息队列,这时管理权交给了looper中,会得到当前线程,把当前线程设置为安全线程(ThreadLocal)因为可以在很多子线程中发送消息给主线程,每个线程要隔离,防止数据混乱,然后把消息加入了消息队列之中,再调用了target.dispatchMessage()方法,target就是handler,把消息分发给handler,就是把消息回调给handler,就完成了一次handler跨线程操作。

13.MVP模式

M(model):差不多就是逻辑处理的地方

V(view):就是Actvivity负责从M中放入和取出数据进行展示

P (presenter):中间人。M和V不能直接互动,要通过P才行。V→P↔M,V把数据给P,P再给M,把数据处理后M交给P,P在交给V。

这样设计的好处:低耦合高内聚,不需要改一处而到处都要改。

14.什么是ANR

应用程序无响应。

  1. 主线程对输入事件在5秒内没有处理完毕
    产生这种ANR的前提是要有输入事件,如果用户没有触发任何输入事件,即便是主线程阻塞了,也不会产生ANR,因为InputDispatcher没有分发事件给应用程序,当然也不会检测处理超时和报告ANR了。即用户在操作APP的过程==输入事件。
  2. 主线程在执行BroadcastReceiver的onReceive函数时10秒内没有执行完毕,后台进程是60秒
    这种情况的ANR系统不会显示对话框提示,仅是输出log而已。
  3. 主线程在执行Service的各个生命周期函数时20秒内没有执行完毕,后台进程为200秒
    同样对这种情况的ANR系统也不会显示对话框提示,仅是输出log。

15.什么是内存泄漏和内存溢出(OOM)

1.内存溢出

系统已经不能再分配出你所需要的空间,比如系统现在只有1G的空间,但是你偏偏要2个G空间,这就叫内存溢出 。就比如每次都加载很多大图片,然后又不释放图片资源,久而久之,图片常驻内存,内存消耗完了就闪退了。

所以图片要及时释放清除.bitmap就是一种存放图片的格式。bitmap.recycler()进行释放。

2.内存泄漏

强引用所指向的对象不会被回收,可能导致内存泄漏,java(jvm)虚拟机宁愿抛出OOM也不会去回收他指向的对象 意思就是你用资源的时候为他开辟了一段空间,当你用完时忘记释放资源了,这时内存还被占用着,一次没关系,但是内存泄漏次数多了就会导致内存溢出 。jvm的作用之一就是清除垃圾,比如一些没有的实例,new出来的对象之类,让内存更友好,也是java一种特有的机制。

handler也会导致内存泄漏。因为handler要处理线程的事情,如果线程没处理完毕,activity主动finished掉了,那么handler就会一直处理线程的事情。解决办法:就是把handler改为静态内部类 static myHandler class extend handler{} 因为静态内部类不会持有外部类的引用。是一个独立的“类”。

也可以用弱引用软引用的方式去解决这个问题。

16.什么是软引用,弱引用,强引用

Java的内存分配和内存回收,都不需要程序员负责,都是由伟大的JVM去负责,一个对象是否可以被回收,主要看是否有引用指向此对象,说的专业点,叫可达性分析。

Java设计这四种引用的主要目的有两个:

  • 可以让程序员通过代码的方式来决定某个对象的生命周期;
  • 有利于垃圾回收。

JVM的知识就不讲了。

1.强引用

强引用是最普遍的一种引用,我们写的代码,99.9999%都是强引用:

Object

new

Object

这种就是强引用了,是不是在代码中随处可见,最亲切。

2.软引用

SoftReferencestudentSoftReference=new SoftReference(new Student());
//软引用就是把对象用SoftReference包裹一下,当我们需要从软引用对象获得包裹的对象,只要get一下就可以了:
Student student = studentSoftReference.get();      
System.out.println(student);

当内存不足,会触发JVM的GC(垃圾回收),如果GC(垃圾回收)后,内存还是不足,就会把软引用的包裹的对象给干掉,也就是只有在内存不足,JVM才会回收该对象。

什么是垃圾回收:

垃圾回收的垃圾就是 无用类,无用的对象等,把无用的类和实例进行清理掉,节约程序运行时的内存。

3.弱引用

跟上面代码类似。用 WeakReference 对象来包裹

弱引用的特点是不管内存是否足够,只要发生GC,都会被回收:

你可能感兴趣的:(Android开发旅途,java,android,github)