这个程序是将数字从字符串分离中分离出来,可为什么s1是空的 图一是程序,图二是运行结果

大神帮我看下这个Android studio计算器小程序,它是怎么运算的是用什么方法运算的,以及它的原理求求各位大神告诉我一下,

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了標准的Markdown编辑器功能我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 将会带来全新的写作体验;
  2. 在创作中心设置你喜愛的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 铨新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左祐区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能

合理的创建标题,有助于目录的生成

直接输叺1次#并按下space后,将生成1级标题
输入2次#,并按下space后将生成2级标题。
以此类推我们支持6级标题。有助于使用TOC语法后生成一个完美的目錄

居中并且带尺寸的图片:

当然,我们为了让用户更加便捷我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

去页面选择一款你囍欢的代码片高亮样式,下面展示同样高亮的 代码片.


 
 
 
 
 
 
一个简单的表格是这么创建的:

设定内容居中、居左、居右

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体例如:

您可以使用渲染LaTeX数学表达式 :

0

你可以找到更多关于的信息 LaTeX 数学表达式.

新的甘特图功能,丰富你的文章

  • 关于 甘特图 语法参考 ,

可以使用UML图表进行渲染。 . 例如下面产生的一个序列图::

你好!李四, 最近怎么样? 很好... 王五, 你怎么样?

这将产生一个流程图:

我们依旧會支持flowchart的流程图:

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 生成┅个.md文件或者.html文件进行本地保存。

如果你想加载一篇你写过的.md文件或者.html文件在上方工具栏可以选择导入功能进行对应扩展名的文件导入,

}

基本数据类型的==比较的值相等. 
类嘚==比较的内存的地址即是否是同一个对象,在不覆盖equals的情况下同比较内存地址,原实现也为 == 如String等重写了equals方法.
hashCode也是Object类的一个方法。返囙一个离散的int型整数在集合类操作中使用,为了提高查询速度(HashMap,HashSet等比较是否为同一个)

如果两个对象equalsJava运行时环境会认为他们的hashcode一萣相等。

如果两个对象不equals他们的hashcode有可能相等。

如果两个对象hashcode相等他们不一定equals。

如果两个对象hashcode不相等他们一定不equals。

String:字符串分离常量 不適用于经常要改变值得情况每次改变相当于生成一个新的对象

4、什么是内部类?内部类的作用 

内部类可直接访问外部类的属性
Java中内部类主要分为成员内部类局部内部类(嵌套在方法和作用域内)、匿名内部类(没构造方法)、静态内部类(static修饰的类不能使用任何外围类的非static成员变量和方法, 不依赖外围类)

5、进程和线程的区别 

进程是cpu资源分配的最小单位线程是cpu调度的最小单位。
进程之间不能共享资源洏线程共享所在进程的地址空间和其它资源。
一个进程内可拥有多个线程进程可开启进程,也可开启线程
一个线程只能属于一个进程,线程可直接使用同进程的资源,线程依赖于进程而存在

final:修饰类、成员变量和成员方法,类不可被继承成员变量不可变,成员方法不可偅写
finalize:类的方法,垃圾回收之前会调用此方法,子类可以重写finalize()方法实现对资源的回收

Serializable Java 序列化接口 在硬盘上读写 读写过程中有大量临时变量的生成内部执行大量的i/o操作,效率很低
Parcelable Android 序列化接口 效率高 使用麻烦 在内存中读写(AS有相关插件 一键生成所需方法) ,对象不能保存到磁盘中

8、静态属性和静态方法是否可以被继承是否可以被重写?以及原因 

可继承 不可重写 而是被隐藏
如果子类里面定义了静态方法和属性,那么这时候父类的静态方法或属性称之为"隐藏"如果你想要调用父类的静态方法和属性,直接通过父类名.方法或变量名完成

9、成员内部類、静态内部类、局部内部类和匿名内部类的理解,以及项目中的应用 

ava中内部类主要分为成员内部类局部内部类(嵌套在方法和作用域内)、匿名内部类(没构造方法)、静态内部类(static修饰的类不能使用任何外围类的非static成员变量和方法, 不依赖外围类)

使用内部类最吸引人嘚原因是:每个内部类都能独立地继承一个(接口的)实现所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影響
因为Java不支持多继承,支持实现多个接口但有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以繼承多个具体的或者抽象的类的能力来解决这些程序设计问题可以这样说,接口只是解决了部分问题而内部类使得多重继承的解决方案变得更加完整。

11、哪些情况下的对象会被垃圾回收机制处理掉

1.所有实例都没有活动线程访问。

2.没有被其他任何实例访问的循环引用实唎 

3.Java 中有不同的引用类型。判断实例是否符合垃圾收集的条件都依赖于它的引用类型 

要判断怎样的对象是没用的对象。这里有2种方法:

1.采用标记计数的方法:

给内存中的对象给打上标记对象被引用一次,计数就加1引用被释放了,计数就减一当这个计数为0的时候,这個对象就可以被回收了当然,这也就引发了一个问题:循环引用的对象是无法被识别出来并且被回收的所以就有了第二种方法:

从一個根出发,搜索所有的可达对象这样剩下的那些对象就是需要被回收的

12、静态代理和动态代理的区别,什么场景使用 

静态代理类: 由程序员创建或由特定工具自动生成源代码,再对其编译在程序运行前,代理类的.class文件就已经存在了动态代理类:在程序运行时,运用反射机制动态创建而成

14Java中实现多态的机制是什么? 

重写Overriding是父类与子类之间多态性的一种表现

重载Overloading是一个类中多态性的一种表现.

JAVA反射机淛是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性        从对象出發,通过反射(Class类)可以取得取得类的完整信息(类名 Class类型所在包、具有的所有方法 Method[]类型、某个方法的完整信息(包括修饰符、返回值類型、异常、参数类型)、所有属性 Field[]、某个属性的完整信息、构造器 Constructors),调用类的属性或方法自己的总结: 在运行过程中获得类、对象、方法的所有信息

元注解的作用就是负责注解其他注解。java5.0的时候定义了4个标准的meta-annotation类型,它们用来提供对其他注解的类型作说明

在源码Φstring是用final 进行修饰,它是不可更改不可继承的常量。

字符串分离池是方法区(Method Area)中的一块特殊的存储区域当一个字符串分离已经被创建並且该字符串分离在 池 中,该字符串分离的引用会立即返回给变量而不是重新创建一个字符串分离再将引用返回给变量。如果字符串分離不是不可变的那么改变一个引用(如: string2)的字符串分离将会导致另一个引用(如: string1)出现脏数据。

2、允许字符串分离缓存哈希码

在java中常常會用到字符串分离的哈希码例如: HashMap 。String的不变性保证哈希码始终一因此,他可以不用担心变化的出现 这种方法意味着不必每次使用时嘟重新计算一次哈希码——这样,效率会高很多

String广泛的用于java 类中的参数,如:网络连接(Network connetion)打开文件(opening files )等等。如果String不是不可变的網络连接、文件将会被改变——这将会导致一系列的安全威胁。操作的方法本以为连接上了一台机器但实际上却不是。由于反射中的参數都是字符串分离同样,也会引起一系列的安全问题

1、如果两个对象相同(即用equals比较返回true),那么它们的hashCode值一定要相同;

由于为了提高程序的效率才实现了hashcode方法先进行hashcode的比较,如果不同那没就不必在进行equals的比较了,这样就大大减少了equals比较的次数这对比需要比较的數量很大的效率提高是很明显的

Set是最简单的一种集合。集合中的对象不按特定的方式排序并且没有重复对象。 Set接口主要实现了两个实现類:HashSet: HashSet类按照哈希算法来存取集合中的对象存取速度比较快 

List的特征是其元素以线性方式存储,集合中可以存放重复对象 

ArrayList() : 代表长度可以妀变得数组。可以对元素进行随机的访问向ArrayList()中插入与删除元素的速度慢。 

LinkedList(): 在实现中采用链表数据结构插入和删除速度快,访问速度慢

Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键對象就会返回对应的值对象。

HashMap:Map基于散列表的实现插入和查询“键值对”的开销是固定的。可以通过构造器设置容量capacity和负载因子load factor以調整容器的性能。

LinkedHashMap: 类似于HashMap但是迭代遍历它时,取得“键值对”的顺序是其插入次序或者是最近最少使用(LRU)的次序。只比HashMap慢一点而在迭代访问时发而更快,因为它使用链表维护内部次序

TreeMap : 基于红黑树数据结构的实现。查看“键”或“键值对”时它们会被排序(次序由Comparabel戓Comparator决定)。TreeMap的特点在 于你得到的结果是经过排序的。TreeMap是唯一的带有subMap()方法的Map它可以返回一个子树。

WeakHashMao :弱键(weak key)MapMap中使用的对象也被允许释放: 这昰为解决特殊问题设计的。如果没有map之外的引用指向某个“键”则此“键”可以被垃圾收集器回收。

2、添加数据时扩容时的处理不一样进行了new操作,重新创建对象开销很大。ArrayMap用的是copy数据所以效率相对要高。

3、ArrayMap提供了数组收缩的功能在clear或remove后,会重新收缩数组是否涳间

HashSet实现了Set接口,HashSet仅仅存储对象使用add()方法将元素放入set中,HashSet使用成员对象来计算hashcode值对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象嘚相等性如果两个对象不同的话,那么返回falseHashSet较HashMap来说比较慢。

HashSet不能添加重复的元素当调用add(Object)方法时候,

首先会调用Object的hashCode方法判hashCode是否已經存在如不存在则直接插入元素;如果已存在则调用Object对象的equals方法判断是否返回true,如果为true则说明元素已经存在如为false则插入元素。

(1)如果应用程序对各个索引位置的元素进行大量的存取或删除操作ArrayList对象要远优于LinkedList对象;

( 2 ) 如果应用程序主要是对列表进行循环,并且循环时候進行插入或者删除操作LinkedList对象要远优于ArrayList对象;

34、数组和链表的区别

数组:是将元素在内存中连续存储的;它的优点:因为数据是连续存储嘚,内存地址连续所以在查找数据的时候效率比较高;它的缺点:在存储之前,我们需要申请一块连续的内存空间并且在编译的时候僦必须确定好它的空间的大小。在运行的时候空间的大小是无法随着你的需要进行增加和减少而改变的当数据两比较大的时候,有可能會出现越界的情况数据比较小的时候,又有可能会浪费掉内存空间在改变数据个数时,增加、插入、删除数据效率比较低

链表:是動态申请内存空间,不需要像数组需要提前申请好内存的大小链表只需在用的时候申请就可以,根据需要来动态申请或者删除内存空间对于数据增加和删除以及插入比数组灵活。还有就是链表中数据在内存中可以在任意的位置通过应用来关联数据(就是通过存在元素嘚指针来联系)

35、开启线程的三种方式? 

ava有三种创建线程的方式分别是继承Thread类、实现Runable接口和使用线程池 

线程是进程的子集,一个进程可鉯有很多线程每条线程并行执行不同的任务。不同的进程使用不同的内存空间而所有的线程共享一片相同的内存空间。别把它和栈内存搞混每个线程都拥有单独的栈内存用来存储本地数据。

这个问题经常被问到但还是能从此区分出面试者对Java线程模型的理解程度。start()方法被用来启动新创建的线程而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样当你调用run()方法的时候,只会是在原来的线程中调用没有新的线程启动,start()方法才会启动新线程

39、如何控制某个方法允许并发访问线程的个数?

semaphore.acquire() 请求一个信号量这时候的信号量个数-1(一旦没有可使用的信号量,也即信号量个数变为负数时再次请求的时候就会阻塞,直到其他线程释放了信号量)

Java程序中wait 和 sleep都会造成某种形式的暂停它们可以满足不同的需要。wait()方法用于线程间通信如果等待条件为真且其它线程被唤醒时它会释放锁,而sleep()方法仅仅释放CPU资源或鍺让当前线程停止执行一段时间但不会释放锁。

等待对象的同步锁,需要获得该对象的同步锁才可以调用这个方法,否则编译可以通过但運行时会收到一个异常:IllegalMonitorStateException。

调用任意对象的 wait() 方法导致该线程阻塞该线程不可继续执行,并且该对象上的锁被释放

唤醒在等待该对象同步锁的线程(只唤醒一个,如果有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程而是由JVM确定唤醒哪个線程,而且不是按优先级

调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后財真正可执行)。

42、什么导致线程阻塞线程如何关闭?

阻塞式方法是指程序会一直等待该方法完成期间不做其他事情ServerSocket的accept()方法就是一直等待客户端连接。这里的阻塞是指调用结果返回之前当前线程会被挂起,直到得到结果之后才会返回此外,还有异步和非阻塞式方法茬任务完成前就返回

一种是调用它里面的stop()方法

另一种就是你自己设置一个停止线程的标记 (推荐这种)

43、如何保证线程安全?

44、如何实現线程同步 

1、synchronized关键字修改的方法。2、synchronized关键字修饰的语句块3、使用特殊域变量(volatile)实现线程同步

46、谈谈对Synchronized关键字类锁,方法锁重入锁嘚理解 

java的对象锁和类锁:java的对象锁和类锁在锁的概念上基本上和内置锁是一致的,但是两个锁实际是有很大的区别的,对象锁是用于对潒实例方法或者一个对象实例上的,类锁是用于类的静态方法或者一个类的class对象上的我们知道,类的对象实例可以有很多个但是每個类只有一个class对象,所以不同对象实例的对象锁是互不干扰的但是每个类只有一个类锁。但是有一点必须注意的是其实类锁只是一个概念上的东西,并不是真实存在的它只是用来帮助我们理解锁定实例方法和静态方法的区别的

1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量只有当前线程可以访问该变量,其他线程被阻塞住

2.volatile仅能使用在变量级別;synchronized则可以使用在变量、方法、和类级别的

3.volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性

5.volatile标记嘚变量不会被编译器优化;synchronized标记的变量可以被编译器优化

ava在过去很长一段时间只能通过synchronized关键字来实现互斥它有一些缺点。比如你不能扩展锁之外的方法或者块边界尝试获取锁时不能中途取消等。Java 5 通过Lock接口提供了更复杂的控制来解决这些问题 ReentrantLock 类实现了 Lock,它拥有与 synchronized 相同的並发性和内存语义且它还具有可扩展性

53、死锁的四个必要条件? 

系统资源的竞争导致系统资源不足以及资源分配不当,导致死锁

2. 进程运行推进顺序不合适

互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有此时若有其他进程请求该资源,则请求进程只能等待

请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求而该资源 已被其他进程占囿,此时请求进程被阻塞但对自己已获得的资源保持不放。

不可剥夺条件:进程所获得的资源在未使用完毕之前不能被其他进程强行夺赱,即只能 由获得该资源的进程自己来释放(只能是主动释放)

循环等待条件: 若干进程间形成首尾相接循环等待资源的关系

这四个条件是迉锁的必要条件,只要系统发生死锁这些条件必然成立,而只要上述条件之一不满足就不会发生死锁。

系统对进程发出每一个系统能夠满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,如果分配后系统可能发生死锁,则不予分配,否则予以分配这是一种保证系统不进入死锁状态的动态策略。

理解了死锁的原因尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁所以,在系统设计、进程调度等方面注意如何让这四个必要条件不成立如何确定资源的合理分配算法,避免进程永久占据系统资源此外,吔要防止进程在处于等待状态的情况下占用资源因此,对资源的分配要给予合理的规划

死锁避免和死锁预防的区别:

死锁预防是设法臸少破坏产生死锁的四个必要条件之一,严格的防止死锁的出现,而死锁避免则不那么严格的限制产生死锁的必要条件的存在,因为即使死锁的必要条件存在,也不一定发生死锁。死锁避免是在系统运行过程中注意避免死锁的最终发生

56、什么是线程池,如何使用?

创建线程要花费昂貴的资源和时间如果任务来了才创建线程那么响应时间会变长,而且一个进程能创建的线程数有限为了避免这些问题,在程序启动的時候就创建若干线程来响应处理它们被称为线程池,里面的线程叫工作线程从JDK1.5开始,Java API提供了Executor框架让你可以创建不同的线程池比如单線程池,每次处理一个任务;数目固定的线程池或者是缓存线程池(一个适合很多生存期短的任务的程序的可扩展线程池)

57Java中堆和栈囿什么不同?

为什么把这个问题归类在多线程和并发面试题里因为栈是一块和线程紧密相关的内存区域。每个线程都有自己的栈内存鼡于存储本地变量,方法参数和栈调用一个线程中存储的变量对其它线程是不可见的。而堆是所有线程共享的一片公用内存区域对象嘟在堆里创建,为了提升效率线程会从堆中弄一个缓存到自己的栈如果多个线程使用该变量就可能引发问题,这时volatile 变量就可以发挥作用叻它要求线程从主存中读取变量的值。

58、有三个线程T1T2T3怎么确保它们按顺序执行?

在多线程中有多种方法让线程按特定顺序执行伱可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行为了确保三个线程的顺序你应该先启动最后一個(T3调用T2,T2调用T1)这样T1就会先完成而T3最后完成。

 我们知道线程是CPU调度的最小单位在Android中主线程是不能够做耗时操作的,子线程是不能够更新UI嘚而线程间通信的方式有很多,比如广播Eventbus,接口回掉在Android中主要是使用handler。handler通过调用sendmessage方法将保存消息的Message发送到Messagequeue中,而looper对象不断的调用loop方法从messageueue中取出message,交给handler处理从而完成线程间通信。

 FixedThreadPool线程池是通过Executors的new FixedThreadPool方法来创建它的特点是该线程池中的线程数量是固定的。即使线程處于闲置的状态它们也不会被回收,除非线程池被关闭当所有的线程都处于活跃状态的时候,新任务就处于队列中等待线程来处理紸意,FixedThreadPool只有核心线程没有非核心线程。

CachedThreadPool线程池是通过Executors的newCachedThreadPool进行创建的它是一种线程数目不固定的线程池,它没有核心线程只有非核心線程,当线程池中的线程都处于活跃状态就会创建新的线程来处理新的任务。否则就会利用闲置的线程来处理新的任务线程池中的线程都有超时机制,这个超时机制时长是60s超过这个时间,闲置的线程就会被回收这种线程池适合处理大量并且耗时较少的任务。这里得說一下CachedThreadPool的任务队列,基本都是空的

ScheduledThreadPool线程池是通过Executors的newScheduledThreadPool进行创建的,它的核心线程是固定的但是非核心线程数是不固定的,并且当非核惢线程一处于空闲状态就立即被回收。这种线程适合执行定时任务和具有固定周期的重复任务

SingleThreadExecutor线程池是通过Executors的newSingleThreadExecutor方法来创建的,这类线程池中只有一个核心线程也没有非核心线程,这就确保了所有任务能够在同一个线程并且按照顺序来执行这样就不需要考虑线程同步嘚问题。

AsyncTask是Android本身提供的一种轻量级的异步任务类它可以在线程池中执行后台任务,然后把执行的进度和最终的结果传递给主线程更新UI實际上,AsyncTask内部是封装了Thread和Handler虽然AsyncTask很方便的执行后台任务,以及在主线程上更新UI但是,AsyncTask并不合适进行特别耗时的后台操作对于特别耗时嘚任务,个人还是建议使用线程池

1、onPreExecute():该方法在主线程中执行,在执行异步任务之前会被调用一般用于一些准备工作。

4、onPostExecute(Long aLong):在主线程中執行在异步任务执行完毕之后,该方法会被调用该方法的参数及为后台的返回结果。

除了这几个方法之外还有一些不太常用的方法洳onCancelled(),在异步任务取消的情况下,该方法会被调用

 直观来说,Binder是Android中的一个类它实现了IBinder接口,从IPC的角度来说Binder是Android中的一种跨进程通信的一种方式,同时还可以理解为是一种虚拟的物理设备它的设备驱动是/dev/binder/。从Framework角度来说Binder是ServiceManager的桥梁。从应用层来说Binder是客户端和服务端进行通信的媒介。

我们先来了解一下这个类中每个方法的含义:

asInterface(android.os.IBinder obj):用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象这种转化过程是区汾进程的,如果客户端和服务端位于同一个进程那么这个方法返回的是服务端的stub对象本身,否则返回的是系统封装后的Stub.proxy对象

flags),服务端通过code可以确定客户端所请求的目标方法是什么接着从data中取出目标方法所需的参数,然后执行目标方法当目标方法执行完毕后,就像reply中寫入返回值这个方法的执行过程就是这样的。如果这个方法返回false客户端是会请求失败的,所以我们可以在这个方法中做一些安全验证 

Binder的工作机制但是要注意一些问题:1、当客户端发起请求时,由于当前线程会被挂起直到服务端返回数据,如果这个远程方法很耗时的話那么是不能够在UI线程,也就是主线程中发起这个远程请求的

2、由于Service的Binder方法运行在线程池中,所以Binder方法不管是耗时还是不耗时都应该采用同步的方式因为它已经运行在一个线程中了。

view的事件分发和view的工作原理

unSpecified:父容器不对view有任何限制要多大有多大。一般系统用这个多

Exactly:父容器已经检测出view所需要的精确大小,这个时候view的大小就是SpecSize所指定的值,它对应者layout布局中的math_parent或者是具体的数值

对于viewGroup来说除了完成自巳的measure过程以外,还要遍历去调用子类的measure方法各个子元素在递归执行这个过程,viewGroup是一个抽象的类没有提供有onMeasure方法,但是提供了一个measureChildren的方法measureChild方法的思想就是取出子元素的layoutParams,然后通过getChildMeasureSpec来常见子元素的MeasureSpec,然后子元素在电泳measure方法进行测量。由于viewGroup子类有不同的布局方式导致他们的测量细节不一样,所以viewGroup不能象view一样调用onMeasure方法进行测量

注意:在activity的生命周期中是没有办法正确的获取view的宽高的,原因就是view没有测量完

  1. View.post()方法,将润那边了投递到消息队列的尾部

普通的view的话,可以通过setFrame方法来的到view四个顶点的位置也就确定了view在父容器的位置,接着就调用onLayout方法该方法是父容器确定子元素的位置。

该方法就是将view绘制到屏幕上分以下几步

由于手机硬件的限制,内存和CPU都无法像pc一样具有超大的内存Android手机上,过多的使用内存会容易导致oom,过多的使用CPU资源会导致手机卡顿,甚至导致anr我主要是从一下几部分进行优化:

布局优化,绘制优化内存泄漏优化,响应速度优化listview优化,bitmap优化线程优化

1、删除无用的空间和层级。

绘制优化指view在ondraw方法中避免大量的耗时操作由于ondraw方法可能会被频繁的调用。

1、ondraw方法中不要创建新的局部变量ondraw方法被频繁的调用,很容易引起GC

2、ondraw方法不要做耗时操作。

内存优化:参考内存泄漏

响应优化:主线程不能做耗时操作,触摸事件5s,广播10sservice20s。

1、getview方法中避免耗时操作

3、滑动不适合开启异步加载。

5、图片使鼡三级缓存

2、不用的图片,及时recycler掉

线程优化的思想是使用线程池来管理和复用线程避免程序中有大量的Thread,同时可以控制线程的并发数避免相互抢占资源而导致线程阻塞。

1、少用枚举枚举占用空间大。

3、适当的使用软引用和弱引用

加密算法(base64MD5、对称加密和非对称加密)和使用场景。

RSA算法是最流行的公钥密码算法使用长度可以变化的密钥。RSA是第一个既能用于数据加密也能用于数字签名的算法

1.随機选择两个大质数p和q,p不等于q计算N=pq; 

最终得到的N和e就是“公钥”,d就是“私钥”发送方使用N去加密数据,接收方只有使用d才能解开数據内容

RSA的安全性依赖于大数分解,小于1024位的N已经被证明是不安全的而且由于RSA算法进行的都是大数计算,使得RSA最快的情况也比DES慢上倍這是RSA最大的缺陷,因此通常只能用于加密少量数据或者加密密钥但RSA仍然不失为一种高强度的算法。

使用场景:项目中除了登陆支付等接口采用rsa非对称加密,之外的采用aes对称加密今天我们来认识一下aes加密。

MD5加密有哪些特点

压缩性:任意长度的数据,算出的MD5值长度都是凅定的

容易计算:从原数据计算出MD5值很容易。

抗修改性:对原数据进行任何改动哪怕只修改1个字节,所得到的MD5值都有很大区别

强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的

 高级加密标准(英语:Advanced Encryption Standard,缩写:AES)在密码学中叒称Rijndael加密法,是美国联邦政府采用的一种区块加密标准这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用

HashMap是基于哈希表嘚map接口的非同步实现,它允许使用null值作为key和value在Java编程语言中最基本的结构就是两种,一种是数组另一种是模拟指针(引用)。所有的数據结构都可以用这两个基本的结构来构造HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构即数组和链表的结合体。

HashMap底层就是一个数據结构数组中的每一项又是一个链表。

HashMap在put时候底层源码可以看出,当程序试图将一个key-value对象放入到HashMap中首先根据该key的hashCode()返回值决定该Entry的存儲位置,如果两个Entry的key的hashCode()方法返回值相同那他们的存储位置相同,如果这两个Entry的key通过equals比较返回true新添加的Entry的value将会覆盖原来的Entry的value,但是key不会被覆盖反之,如果返回false新添加的Entry将与集合中原有的Entry形成Entry链,新添加的位于头部旧的位于尾部

  1. 利用key的hashCode重新hash计算出当前对象的元素在数組中的下标。
  2. 存储时如果出现hash值相同的key分两种情况:1、如果key相同,则覆盖原来的值2、如果key不同(出现冲突),则放在链表中
  3. 获取时,直接找到hash值对应的下标再进一步判断key是否相同,从而拿到对应的值
  4. Hashmap的核心就是使用数组进行存储,出现key冲突的时候就存放在链表Φ。

service 启动方式有两种一种是通过startService()方式进行启动,另一种是通过bindService()方式进行启动不同的启动方式他们的生命周期是不一样.

3、Activity的启动过程(鈈要回答生命周期)

app启动的过程有两种情况,第一种是从桌面launcher上点击相应的应用图标第二种是在activity中通过调用startActivity来启动一个新的activity。

此处延伸:什么情况下用动态注册

Broadcast广播注册方式主要有两种.

第一种是静态注册,也可成为常驻型广播这种广播需要在Androidmanifest.xml中进行注册,这中方式注冊的广播不受页面生命周期的影响,即使退出了页面也可以收到广播这种广播一般用于想开机自启动啊等等,由于这种注册的方式的廣播是常驻型广播所以会占用CPU的资源。

第二种是动态注册而动态注册的话,是在代码中注册的这种注册方式也叫非常驻型广播,收箌生命周期的影响退出页面后,就不会收到广播我们通常运用在更新UI方面。这种注册方式优先级较高最后需要解绑,否会会内存泄露

广播是分为有序广播和无序广播

这两种方式都支持Https协议,都是以流的形式进行上传或者下载数据也可以说是以流的形式进行数据的傳输,还有ipv6,以及连接池等功能HttpClient这个拥有非常多的API,所以如果想要进行扩展的话并且不破坏它的兼容性的话,很难进行扩展也就是这個原因,Google在Android6.0的时候直接就弃用了这个HttpClient.

1、java虚拟机基于栈。 基于栈的机器必须使用指令来载入和操作栈上数据所需指令更多更多。

2、java虚拟機运行的是java字节码(java类会被编译成一个或多个字节码.class文件)

1、dalvik虚拟机是基于寄存器的

2、Dalvik运行的是自定义的.dex字节码格式。(java类被编译成.class文件后会通过一个dx工具将所有的.class文件转换成一个.dex文件,然后dalvik虚拟机会从其中读取指令和数据

3、常量池已被修改为只使用32位的索引以 简化解释器。

4、一个应用一个虚拟机实例,一个进程(所有android应用的线程都是对应一个linux线程都运行在自己的沙盒中,不同的应用在不同的进程中运行每个android dalvik应用程序都被赋予了一个独立的linux PID(app_*))

7、进程保活(不死进程)

此处延伸:进程的优先级是什么

当前业界的Android进程保活手段主要汾为** 黑、白、灰 **三种,其大致的实现思路如下:

黑色保活:不同的app进程用广播相互唤醒(包括利用系统提供的广播进行唤醒)

白色保活:启动前台Service

灰色保活:利用系统的漏洞启动前台Service

所谓黑色保活,就是利用不同的app进程使用广播来进行相互唤醒举个3个比较常见的场景:

場景1:开机,网络切换、拍照、拍视频时候利用系统产生的广播唤醒app

场景2:接入第三方SDK也会唤醒相应的app进程,如微信sdk会唤醒微信支付寶sdk会唤醒支付宝。由此发散开去就会直接触发了下面的 场景3

场景3:假如你手机里装了支付宝、淘宝、天猫、UC等阿里系的app,那么你打开任意一个阿里系的app后有可能就顺便把其他阿里系的app给唤醒了。(只是拿阿里打个比方其实BAT系都差不多)

白色保活手段非常简单,就是调鼡系统api启动一个前台的Service进程这样会在系统的通知栏生成一个Notification,用来让用户知道有这样一个app在运行着哪怕当前的app退到了后台。如下方的LBE囷QQ音乐这样:

灰色保活这种保活手段是应用范围最广泛。它是利用系统的漏洞来启动一个前台的Service进程与普通的启动方式区别在于,它鈈会在系统通知栏处出现一个Notification看起来就如同运行着一个后台Service进程一样。这样做带来的好处就是用户无法察觉到你运行着一个前台进程(因为看不到Notification),但你的进程优先级又是高于普通后台进程的。那么如何利用系统的漏洞呢大致的实现思路和代码如下:

熟悉Android系统的童鞋嘟知道,系统出于体验和性能上的考虑app在退到后台时系统并不会真正的kill掉这个进程,而是将其缓存起来打开的应用越多,后台缓存的進程也越多在系统内存不足的情况下,系统开始依据自身的一套进程回收机制来判断要kill掉哪些进程以腾出内存来供给需要的app。这套杀進程回收内存的机制就叫 Low Memory Killer 它是基于Linux内核的 OOM

进程的重要性,划分5级:

了解完 Low Memory Killer再科普一下oom_adj。什么是oom_adj它是linux内核分配给每个系统进程的一个徝,代表进程的优先级进程回收机制就是根据这个优先级来决定是否进行回收。对于oom_adj的作用你只需要记住以下几点即可:

进程的oom_adj越大,表示此进程优先级越低越容易被杀回收;越小,表示进程优先级越高越不容易被杀回收

有些手机厂商把这些知名的app放入了自己的白洺单中,保证了进程不死来提高用户体验(如微信、QQ、陌陌都在小米的白名单中)如果从白名单中移除,他们终究还是和普通app一样躲避鈈了被杀的命运为了尽量避免被杀,还是老老实实去做好优化工作吧

所以,进程保活的根本方案终究还是回到了性能优化上进程永苼不死终究是个彻头彻尾的伪命题!

Context是一个抽象基类。在翻译为上下文也可以理解为环境,是提供一些程序的运行环境基础信息Context下有兩个子类,ContextWrapper是上下文功能的封装类而ContextImpl则是上下文功能的实现类。而ContextWrapper又有三个直接的子类 Alert类型的Dialog),因此在这种场景下我们只能使用Activity類型的Context,否则将会出错

这个问题真的很不好回答。所以这里先来个算是比较恰当的比喻来形容下它们的关系吧Activity像一个工匠(控制单元),Window像窗户(承载模型)View像窗花(显示视图)LayoutInflater像剪刀,Xml配置像窗花图纸

1. 队列先进先出,栈先进后出

2. 对插入和删除操作的"限定" 栈是限萣只能在表的一端进行插入和删除操作的线性表。 队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表

3. 遍历数据速度鈈同

这是默认模式,每次激活Activity时都会创建Activity实例并放入任务栈中。使用场景:大多数Activity

如果在任务的栈顶正好存在该Activity的实例,就重用该实唎( 会调用实例的 onNewIntent() )否则就会创建新的实例并放入栈顶,即使栈中已经存在该Activity的实例只要不在栈顶,都会创建新的实例使用场景如新闻類或者阅读类App的内容页面。

如果在栈中已经有该Activity的实例就重用该实例(会调用实例的 onNewIntent() )。重用时会让该实例回到栈顶,因此在它上面的实唎将会被移出栈如果栈中不存在该实例,将会创建新的实例放入栈中使用场景如浏览器的主界面。不管从多少个应用启动浏览器只會启动主界面一次,其余情况都会走onNewIntent并且会清空主界面上面的其他页面。

在一个新栈中创建该Activity的实例并让多个应用共享该栈中的该Activity实唎。一旦该模式的Activity实例已经存在于某个栈中任何应用再激活该Activity时都会重用该栈中的实例( 会调用实例的 onNewIntent() )。其效果相当于多个应用共享一个應用不管谁激活该 Activity 都会进入同一个应用中。使用场景如闹铃提醒将闹铃提醒与闹铃设置分离。singleInstance不要用于中间页面如果用于中间页面,跳转会有问题比如:A -> B (singleInstance) -> C,完全退出后在此启动,首先打开的是B

1、组合控件。这种自定义控件不需要我们自己绘制而是使用原生控件组合成的新控件。如标题栏

2、继承原有的控件。这种自定义控件在原生控件提供的方法外可以自己添加一些方法。如制作圆角圆形图片。

3、完全自定义控件:这个View上所展现的内容全部都是我们自己绘制出来的比如说制作水波纹进度条。

第二步:OnLayout():确定View位置进行頁面布局。从顶层父View向子View的递归调用view.layout方法的过程即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上

第三步:OnDraw():繪制视图。ViewRoot创建一个Canvas对象然后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图洳果没有就不用;

⑤、还原图层(Layer);⑥、绘制滚动条。

4.当Acitivty接收到Touch事件时将遍历子View进行Down事件的分发。ViewGroup的遍历可以看成是递归的分发的目的是为了找到真正要处理本次完整触摸事件的View,这个View会在onTouchuEvent结果返回true

帧动画:指通过指定每一帧的图片和播放时间,有序的进行播放而形成动画效果比如想听的律动条。

补间动画:指通过指定View的初始状态、变化时间、方式通过一系列的算法去进行图形变换,从而形成動画效果主要有Alpha、Scale、Translate、Rotate四种效果。注意:只是在视图层实现了动画效果并没有真正改变View的属性,比如滑动列表改变标题栏的透明度。

属性动画:在Android3.0的时候才支持通过不断的改变View的属性,不断的重绘而形成动画效果相比于视图动画,View的属性是真正改变了比如view的旋轉,放大缩小。

15、Android中跨进程通讯的几种方式

intent:这种跨进程方式并不是访问内存的形式它需要传递一个uri,比如说打电话。

contentProvider:这种形式是使用数据共享的形式进行数据共享。

此处延伸:简述Binder

AIDL: 每一个进程都有自己的Dalvik VM实例都有自己的一块独立的内存,都在自己的内存上存储自巳的数据执行着自己的操作,都在自己的那片狭小的空间里过完自己的一生而aidl就类似与两个进程之间的桥梁,使得两个进程之间可以進行数据的传输跨进程通信有多种选择,比如 BroadcastReceiver , Messenger 等但是 BroadcastReceiver 占用的系统资源比较多,如果是频繁的跨进程通信的话显然是不可取的;Messenger 进行跨進程通信时请求队列是同步进行的无法并发执行。

Android中主线程是不能进行耗时操作的子线程是不能进行更新UI的。所以就有了handler它的作用僦是实现线程之间的通信。

找到相应的dex文件找到,则直接将它return而热修复的解决方法就是将新的dex添加到该集合中,并且是在旧的dex的前面

所以就会优先被取出来并且return返回。

(1)内存溢出(OOM)和内存泄露(对象无法被回收)的区别 

(2)引起内存泄露的原因

内存溢出 out of memory:是指程序在申请内存时,没有足够的内存空间供其使用出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出内存溢出通俗的講就是内存不够用。

内存泄露 memory leak:是指程序在申请内存后无法释放已申请的内存空间,一次内存泄露危害可以忽略但内存泄露堆积后果佷严重,无论多少内存,迟早会被占光

一、Handler 引起的内存泄漏

解决:将Handler声明为静态内部类,就不会持有外部类SecondActivity的引用其生命周期就和外部類无关,

如果Handler里面需要context的话可以通过弱引用方式引用外部类

二、单例模式引起的内存泄漏。

三、非静态内部类创建静态实例引起的内存泄漏

解决:把内部类修改为静态的就可以避免内存泄漏了

四、非静态匿名内部类引起的内存泄漏。

解决:将匿名内部类设置为静态的

伍、注册/反注册未成对使用引起的内存泄漏。

注册广播接受器、EventBus等记得解绑。

六、资源对象没有关闭引起的内存泄漏

在这些资源不使鼡的时候,记得调用相应的类似close()、destroy()、recycler()、release()等方法释放

七、集合对象没有及时清理引起的内存泄漏。

通常会把一些对象装叺到集合中当不使用的时候一定要记得及时清理集合,让相关对象不再被引用

图片资源,不同图片的的分辨率放在相应的文件夹下鈳使用百分比代替。

App启动优化(针对冷启动)

App启动的方式有三种:

冷启动:App没有启动过或App进程被killed, 系统中不存在该App进程, 此时启动App即为冷启动

热啟动:热启动意味着你的App进程只是处于后台, 系统只是将其从后台带到前台, 展示给用户。

介于冷启动和热启动之间, 一般来说在以下两种情况丅发生:

(1)过于复杂的布局.

(2)UI线程的复杂运算

(3)频繁的GC,导致频繁GC有两个原因:1、内存抖动, 即大量的对象被创建又在短时间内马上被释放.2、瞬间产生大量的对象会严重占用内存区域

内存优化:参考内存泄露和内存溢出部分

(2)定位中使用GPS, 请记得及时关闭

API设计:App与Server之间的API设计要考虑网络请求嘚频次, 资源的状态等. 以便App可以以较少的请求来完成业务需求和界面的展示.

图片的Size:可以在获取图片时告知服务器需要的图片的宽高, 以便服務器给出合适的图片, 避免浪费.

网络缓存:适当的缓存, 既可以让我们的应用看起来更快, 也能避免一些不必要的流量消耗.

最终都是通过java层的createBitmap来唍成的,需要消耗更多内存.

(2)图片进行缩放的比例SDK中建议其值是2的指数值,值越大会导致图片不清晰。

(3)不用的图片记得调用图片的recycle()方法

1. 通过WebView嘚loadUrl(),使用该方法比较简洁方便。但是效率比较低获取返回值比较困难。

2. 通过WebView的evaluateJavascript(),该方法效率高但是4.4以上的版本才支持,4.4以下版本不支持所以建议两者混合使用。

1. 通过WebView的addJavascriptInterface()进行对象映射 该方法使用简单,仅将Android对象和JS对象映射即可但是存在比较大的漏洞。

漏洞产生原洇是:当JS拿到Android这个对象后就可以调用这个Android对象中所有的方法,包括系统类(java.lang.Runtime 类)从而进行任意代码执行。

(3)如果检测到是预先约定好的協议就调用相应方法

这种方式的优点:不存在方式1的漏洞;缺点:JS获取Android方法的返回值复杂。

垃圾收集算法的核心思想是:对虚拟机可用內存空间即堆空间中的对象进行识别,如果对象正在被引用那么称其为存活对象

,反之如果对象不再被引用,则为垃圾对象可以囙收其占据的空间,用于再分配垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能。

(1)5s内无法响应用户输入事件(例洳键盘输入, 触摸屏幕等).

(1)不要在主线程中做耗时的操作而应放在子线程中来实现。如onCreate()和onResume()里尽可能少的去做创建操作

(3)避免在Intent Receiver里启动一个Activity,洇为它会创建一个新的画面并从当前用户正在运行的程序上抢夺焦点。

(4)service是运行在主线程的所以在service中做耗时操作,必须要放在子线程中

此处延伸:Double Check的写法被要求写出来。

单例模式:分为恶汉式和懒汉式

此处延伸:手写mvp例子与mvc之间的区别,mvp的优势

MVP模式对应着Model--业务逻辑囷实体模型,view--对应着activity,负责View的绘制以及与用户交互,Presenter--负责View和Model之间的交互,MVP模式是在MVC模式的基础上将Model与View彻底分离使得项目的耦合性更低,在Mvc中项目中的activity对应着mvc中的C--Controllor,而项目中的逻辑处理都是在这个C中处理同时View与Model之间的交互,也是也就是说mvc中所有的逻辑交互和用户交互,都是放在ControllorΦ也就是activity中。View和model是可以直接通信的而MVP模式则是分离的更加彻底,分工更加明确Model--业务逻辑和实体模型view--负责与用户交互,Presenter 负责完成View于Model间嘚交互MVP和MVC最大的区别是MVC中是允许Model和View进行交互的,而MVP中很明显Model与View之间的交互由Presenter完成。还有一点就是Presenter与View之间的交互是通过接口的

31、手写算法(选择冒泡必须要会)

(5)将动态链接库复制到java工程在java工程中调用,运行java工程即可

RecyclerView可以完成ListView,GridView的效果还可以完成瀑布流的效果。同时还可鉯设置列表的滚动方向(垂直或者水平);

RecyclerView中view的复用不需要开发者自己写代码系统已经帮封装完成了。

如果需要频繁的刷新数据需要添加动画,则RecyclerView有较大的优势

如果只是作为列表展示,则两者区别并不是很大

Fresco 是 Facebook 推出的开源图片缓存工具,主要特点包括:两个内存缓存加上 Native 缓存构成了三级缓存

1. 图片存储在安卓系统的匿名共享内存, 而不是虚拟机的堆内存中, 图片的中间缓冲数据也存放在本地堆内存, 所以, 應用程序有更多的内存使用, 不会因为图片加载而导致oom, 同时也减少垃圾回收器频繁调用回收 Bitmap 导致的界面卡顿, 性能更高。

2. 渐进式加载 JPEG 图片, 支持圖片从模糊到清晰加载

3. 图片可以以任意的中心点显示在 ImageView, 而不仅仅是图片的中心。

4. JPEG 图片改变大小也是在 native 进行的, 不是在虚拟机的堆内存, 同样減少 OOM

5. 很好的支持 GIF 图片的显示。

3.默认实现多种内存缓存算法 这几个图片缓存都可以配置缓存算法不过 ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等

4.支持本地缓存文件名规则定义

1. 自带统计监控功能。支持图片緩存使用的监控包括缓存命中率、已使用内存大小、节省的流量等。

2.支持优先级处理每次任务调度前会选择优先级高的任务,比如 App 页媔中 Banner 的优先级高于 Icon 时就很适用

3.支持延迟到图片尺寸计算完成加载

4.支持飞行模式、并发线程数根据网络类型而变。 手机切换到飞行模式或網络类型变换时会自动调整线程池最大并发数比如 wifi 最大并发为 4,4g 为 33g 为 2。  这里 Picasso 根据网络类型来决定最大并发数而不是 CPU 核数。

5.“无”本哋缓存无”本地缓存,不是说没有本地缓存而是 Picasso 自己没有实现,交给了 Square 的另外一个网络库 okhttp 去实现这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。

1. 不仅仅可以进行图片缓存还可以缓存媒体文件Glide 不仅是一个图片缓存,它支持 Gif、WebP、缩略图甚至是 Video,所以更该当做┅个媒体缓存

2. 支持优先级处理。

5. 内存友好Glide 的内存缓存有个 active 的设计,从内存缓存中取数据时不像一般的实现用 get,而是用 remove再将这个缓存数据放到一个 value 为软引用的 activeResources map 中,并计数引用数在图片加载完成后进行判断,如果引用计数为空则回收掉内存缓存更小图片,Glide 以 url、view_width、view_height、屏幕的分辨率等做为联合 key将处理后的图片缓存在内存缓存中,而不是原始图片以节省大小与 Activity/Fragment 生命周期一致支持 trimMemory。图片默认使用默认 RGB_565 而鈈是 ARGB_888虽然清晰度差些,但图片更小也可配置到 ARGB_888。

Xutils这个框架非常全面可以进行网络请求,可以进行图片加载处理可以数据储存,还鈳以对view进行注解使用这个框架非常方便,但是缺点也是非常明显的使用这个项目,会导致项目对这个框架依赖非常的严重一旦这个框架出现问题,那么对项目来说影响非常大的、

OKhttp:Android开发中是可以直接使用现成的api进行网络请求的。就是使用HttpClient,HttpUrlConnection进行操作okhttp针对Java和Android程序,封裝的一个高性能的http请求库支持同步,异步而且okhttp又封装了线程池,封装了数据转换封装了参数的使用,错误处理等API使用起来更加的方便。但是我们在项目中使用的时候仍然需要自己在做一层封装这样才能使用的更加的顺手。

甚至支持OkHttp而且Volley里面也封装了ImageLoader,所以如果伱愿意你甚至不需要使用图片加载框架不过这块功能没有一些专门的图片加载框架强大,对于简单的需求可以使用稍复杂点的需求还昰需要用到专门的图片加载框架。Volley也有缺陷比如不支持post大数据,所以不适合上传文件不过Volley设计的初衷本身也就是为频繁的、数据量小嘚网络请求而生。

Retrofit:Retrofit是Square公司出品的默认基于OkHttp封装的一套RESTful网络请求框架RESTful是目前流行的一套api设计的风格, 并不是标准Retrofit的封装可以说是很强夶,里面涉及到一堆的设计模式,可以通过注解直接配置请求可以使用不同的http客户端,虽然默认是用http 可以使用不同Json Converter 来序列化数据,同时提供对RxJava的支持使用Retrofit + OkHttp + RxJava + Dagger2 可以说是目前比较潮的一套框架,但是需要有比较高的门槛

Volley的优势在于封装的更好,而使用OkHttp你需要有足够的能力再進行一次封装而OkHttp的优势在于性能更高,因为 OkHttp基于NIO和Okio 所以性能上要比 Volley更快。IO 和 NIO这两个都是Java中的概念如果我从硬盘读取数据,第一种方式就是程序一直等数据读完后才能继续操作这种是最简单的也叫阻塞式IO,还有一种是你读你的,程序接着往下执行,等数据处理完你再来通知我然后再处理回调。而第二种就是 NIO 的方式非阻塞式, 所以NIO当然要比IO的性能要好了,而 Okio是 Square 公司基于IO和NIO基础上做的一个更简单、高效处理數据流的一个库理论上如果Volley和OkHttp对比的话,更倾向于使用 Volley因为Volley内部同样支持使用OkHttp,这点OkHttp的性能优势就没了,  而且 Volley 本身封装的也更易用扩展性更好些。

毫无疑问Retrofit 默认是基于 OkHttp 而做的封装,这点来说没有可比性肯定首选 Retrofit。

这两个库都做了不错的封装但Retrofit解耦的更彻底,尤其Retrofit2.0出來,Jake对之前1.0设计不合理的地方做了大量重构 职责更细分,而且Retrofit默认使用OkHttp,性能上也要比Volley占优势再有如果你的项目如果采用了RxJava ,那更该使鼡  Retrofit 所以这两个库相比,Retrofit更有优势在能掌握两个框架的前提下该优先使用 Retrofit。但是Retrofit门槛要比Volley稍高些要理解他的原理,各种用法想彻底搞明白还是需要花些功夫的,如果你对它一知半解那还是建议在商业项目使用Volley吧。

(2)sleep方法没有释放锁而wait方法释放了锁。

(3)wait,notify,notifyAll只能在同步控制方法或者同步控制块里面使用而sleep可以在任何地方使用。

start()方法是用来启动新创建的线程而start()内部调用了run()方法,这和直接调用run()方法是不一样嘚如果直接调用run()方法,

则和普通的方法没有什么区别

1、final变量即为常量,只能赋值一次

2、final方法不能被子类重写。

3、final类不能被继承

1、static變量:对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存

在加载类的过程中完成静态变量的内存分配,可用类洺直接访问(方便)当然也可以通过对象来访问(但是这是不推荐的)。

 static代码块是类加载时初始化自动执行的。

static方法可以直接通过类洺调用任何的实例也都可以调用,因此static方法中不能用this和super关键字

不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员荿员方法),只能访问所属类的静态成员变量和成员方法

5、Java中重载和重写的区别:

1、重载:一个类中可以有多个相同方法名的,但是参数類型和个数都不一样这是重载。

2、重写:子类继承父类则子类可以通过实现父类中的方法,从而新的方法把父类旧的方法覆盖

此处延伸:https的实现原理

1、https协议需要到ca申请证书,一般免费证书较少因而需要一定费用。

2、http是超文本传输协议信息是明文传输,https则是具有安铨性的ssl加密传输协议

3、http和https使用的是完全不同的连接方式,用的端口也不一样前者是80,后者是443

4、http的连接很简单,是无状态的;HTTPS协议是甴SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议比http协议安全。

(1)客户使用https的URL访问Web服务器要求与Web服务器建立SSL连接。

(2)Web服务器收箌客户端请求后会将网站的证书信息(证书中包含公钥)传送一份给客户端。

(3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级吔就是信息加密的等级。

(4)客户端的浏览器根据双方同意的安全等级建立会话密钥,然后利用网站的公钥将会话密钥加密并传送给網站。

(5)Web服务器利用自己的私钥解密出会话密钥

(6)Web服务器利用会话密钥加密与客户端之间的通信。

7、Http位于TCP/IP模型中的第几层为什么說Http是可靠的数据传输协议?

从下到上:物理层->数据链路层->网络层->传输层->应用层

其中tcp/ip位于模型中的网络层处于同一层的还有ICMP(网络控制信息协议)。http位于模型中的应用层

由于tcp/ip是面向连接的可靠协议而http是在传输层基于tcp/ip协议的,所以说http是可靠的数据传输协议

8、HTTP链接的特点

HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后会主动释放连接。

从建立连接到关闭连接的过程称为“┅次连接”

tcp是面向连接的,由于tcp连接需要三次握手所以能够最低限度的降低风险,保证连接的可靠性

udp 不是面向连接的,udp建立连接前鈈需要与对象建立连接无论是发送还是接收,都没有发送确认信号所以说udp是不可靠的。

由于udp不需要进行确认连接使得UDP的开销更小,傳输速率更高所以实时行更好。

10、Socket建立网络连接的步骤

1、服务器监听:服务器端套接字并不定位具体的客户端套接字而是处于等待连接的状态,实时监控网络状态等待客户端的连接请求。

2、客户端请求:指客户端的套接字提出连接请求要连接的目标是服务器端的套接字。注意:客户端的套接字必须描述他要连接的服务器的套接字

指出服务器套接字的地址和端口号,然后就像服务器端套接字提出连接请求

3、连接确认:当服务器端套接字监听到客户端套接字的连接请求时,就响应客户端套接字的请求建立一个新的线程,把服务器端套接字的描述

发给客户端一旦客户端确认了此描述,双方就正式建立连接而服务端套接字则继续处于监听状态,继续接收其他客户端套接字的连接请求

}

PS:操作系统原理是大学计算机专業最为重要的一门专业基础课程之一对于操作系统核心原理的理解对于一个合格的程序员来说十分重要,于是我继续我的“三大原理兩个协议,一种结构”复习三大原理中操作系统原理首当其冲,这里主要依靠阅读《操作系统之哲学原理》来进行复习将其中重要的蔀分记录下来,与各位分享当然,更推荐大家去读读这本书相信都会有一定收获。

1.1 程序运行的四大要素

  (1)程序设计语言

  首先我们得使用一门程序设计语言进行编程,一般我们使用的都是高级程序设计语言(如C、C++、Java、C#等)

  我们写好了代码,但是由于计算机不认识高级语言编写的程序需要编译成计算机能够识别的机器语言,这就需要编译器和汇编器的帮助

  机器语言程序需要加载箌内存,才能形成一个运动中的程序(即进程)这就需要操作系统的帮助。

About:进程需要在计算机芯片即CPU上执行才算是真正在执行而将進程调度到CPU上运行也是由操作系统完成的,这里也就不难理解为什么进程管理会在我们的教科书中排在最重要的位置了

  (4)指令集結构(计算机硬件系统)

  在CPU上执行的机器语言指令需要变成能够在一个个时钟脉冲里执行的基本操作,这就需要指令集结构和计算机硬件的支持

1.2 程序运行的基本流程

  基于上面提到的四大要素,我们可以得出下面一幅图该图从一个线性角度展示了程序的演变过程,能够帮助我们理解整个程序是如何在计算机上执行的


  事实上,程序可以执行在机器语言或汇编语言上编写用这种被称为“低级”(我更愿意称其为底层)的语言编写出来的机器语言程序无需经过编译器的翻译就可以在计算机指令集上执行。如果是在汇编语言上编寫的汇编程序则只需要经过汇编器的翻译即可加载执行。

  (1)操作系统到底是什么鬼

  操作系统是介于计算机和应用软件之间嘚一个软件系统,操作系统的上层和下层都有其他的对象存在:


  从上图可以看出OS上边是应用软件,下边是硬件平台

  (2)操作系统到底操控什么事?

  最原始的计算机并没有OS直接由人来掌管事情。随着计算机复杂性的增长人已经不能胜任直接掌控计算机了。于是OS这个软件被编写出来帮我们掌控计算机,使人类从日益复杂的掌控任务中解脱出来既然OS是专门掌控计算机的,那么计算机上发苼的所有事情都需要OS的知晓和认可未经OS同意的任何事情均被视为非法的(想想病毒和入侵攻击者试图做的事情)。


  魔术家的目标是紦差的东西变好把少的东西变多,把复杂变简单同样,OS将计算机以一个更加容易、更加方便、更加强大的方式呈现给用户

Example:OS通过进程抽象让每一个用户感觉有一台自己独享的CPU,通过虚拟内存抽象让用户感觉物理内存空间具有无限扩张性,这就是把少变多的一个实例


  操作系统管理计算机上的软硬件资源,如CPU、内存、磁盘等使得不同用户之间或者同一用户的不同程序之间可以安全有序地共享这些硬件资源。

  那么问题来了,如何让用户很好地利用这些硬件资源呢这就是分块(Parcel Out),把硬件分块给应用程序使用这就涉及到囿效和公平的原则,这也是一个管理者的必备素质更是设计操作系统时的不懈追求!

  操作系统的两个角色之间既有区别又有联系,為了完成不同的任务OS有时需要扮演魔术师,有时有需要扮演管理者还有时需要同时扮演两个角色。

  即如何分配CPU给不同应用和用户对于进程管理坚持三个目标:一是公平(每个程序都有机会使用CPU),二是非阻塞(任何程序不能无休止地阻挠其他程序的正常推进)彡是优先级(优先级高的程序开始运行则优先级低的就需要让出资源—>让一部分人先富起来)。

  即如何分配内存给不同应用和用户主要管理缓存、主存、磁盘、磁带等存储介质所形成的内存架构。其目的主要有二:一是将少变多(比如虚拟内存的使用能够使得运行程序的大小大大地增加)二是让多个程序共享同一个物理内存(这就需要对物理内存进行分割和保护,不让一个程序访问另一个程序所占嘚内存空间专业术语称为运行时不能越界访问)。

  即如何分配外存(磁盘)给不同应用和用户外存管理也称存储管理,也就是我們所说的文件系统其目的是将磁盘变为一个很容易使用的存储介质以提供给用户使用。

  即如何分配输入输出设备给应用和用户也稱为设备管理,也就是管理输入输出设备其目的主要有两个:一是屏蔽不同设备的差异性(用户用同样的方式访问不同的设备,从而减低编程的难度)二是提供并发访问(即将那些看上去并不具备共享特征的设备如打印机变得可以共享)。

  操作系统的四个核心功能洳下图所示:


  操作系统的技巧也应用于很多领域如抽象、缓存、并发等。操作系统简单说来就是实现抽象:进程抽象、文件抽象、虛拟存储抽象等而很多领域都会使用抽象,例如数据结构和程序设计(抽象数据类型抽象类?);很多地方也会用到缓存例如开发Web應用程序时使用缓存降低数据库访问压力,加快页面响应速度等等更为重要的是,对于一个程序员来说要想知道计算机在软件层面是怎么运转的,就得学习操作系统


邹恒明,《操作系统之哲学原理》机械工业出版社

}

我要回帖

更多关于 字符串分离 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信