资讯详情

2020 android面试题答案

(1)java面试题(基础 高级)(必须) java中==和equals和hashCode的区别 ==用于比较两个值和两个对象的内存地址是否相等; equals是Object默认情况下,比较两个对象是否为同一对象,内部实现是通过==来实现的。 如果你想比较两个对象的其他内容,可以重写equals方法, hashCoed也是Object类中的方法,返回值是对象的哈希码,同一对象的哈希码必须相等,但不同对象的哈希码也可能相等。 假如两个对象equals,Java运行时,环境会认为它们hashcode一定相等。 如果两个对象不是equals,他们的hashcode可能相等。 假如两个对象hashcode等待,他们不一定equals。 如果有两个对象hashcode不平等,他们一定不能equals。

int、char、long各占多少字节数(笔试题多出现) Int:4字节 chat:2字节 long\double:8字节

int与integer的区别 (笔试) 1、Integer是int的包装类,int则是java基本数据类型 2、Integer变量只能在实例化后使用,int变量不需要 3、Integer实际是对象的引用,当new一个Integer实际上,生成指针指向这个对象;而int直接存储数据值 4、Integer的默认值是null,int的默认值是0

谈谈对java多态的理解 多态性是指父类引用指向子类对象,在执行过程中判断引用对象的实际类型,并根据实际类型调用相应的方法。(同一消息可以根据不同的发送对象采用多种不同的行为方式。

多态作用:消除类型之间的耦合关系。

实现多态化的技术称为动态绑定(dynamic binding),是指根据实际类型调用相应的方法,判断执行期间引用对象的实际类型。

实现多态性的三个要素:继承和重写,父类引用指向子类对象(即声明是父类,实际指向子类对象)

String、StringBuffer、StringBuilder区别 1、三者在执行速度上:StringBuilder > StringBuffer > String (由于String是常量,不可改变,拼接时会重新创建新对象)。 2、StringBuffer线程安全,StringBuilder线程不安全。StringBuffer有缓冲区)

什么是内部类?内部类的作用? 内部类:在另一个类或方法中定义一个类,称为内部类。 功能:1。每个内部类别都可以独立继承一个接口的实现,因此外部类别是否继承了某个(接口)的实现对内部类别没有影响。内部类使多继承的解决方案完整, 2.方便组织有一定逻辑关系的类组织,隐藏外界。 3.方便编写事件驱动程序 4.方便编写线程代码

抽象与界面的区别 相同: 都可以继承 2.继承类必须实现未实现的函数 3.只关注方法的定义,不关注方法的实现 差异: 一个子类可以继承多个接口,但只能继承一个父类 2.抽象只能在对象中表示一个对象,接口可以由许多对象继承

抽象与界面的应用场景 如果你有一些方法,想让它们中的一些默认实现,那就用抽象。 若要实现多重继承,则必须使用接口。Java不支持多继承,子类不能继承多个类,但可以实现多个接口。因此,您可以使用接口来解决它。 如果基本功能不断变化,则需要使用抽象类。如果基本功能和接口不断变化,则需要改变实现接口的所有类别。

没有方法和属性法和属性吗? 抽象类专门用于衍生子类,子类必须实现抽象类声明的抽象方法,否则子类仍然是抽象类。 抽象方法必须是抽象方法,但抽象方法不一定是抽象方法。 抽象类中可以没有抽象方法,但有抽象方法的一定是抽象类。所以,java中 抽象类没有抽象方法。 抽象的作用在于子类的继承和实现,即多态;抽象的存在价值在于:实例没有意义,因为类已经定义,不能改变方法,但实例对象不能满足要求,只有继承和重写其子类才能满足要求。因此,它被定义为没有抽象方法的抽象

泛型中extends和super的区别 1、< extends T>上界限制参数类型:参数类型必须是T或TT的子类型 下界限制参数类型:参数类型必须是T或TT的超类型 2、只能用于方法返回,告诉编译器此返回的类型的最小继承边界是T,T可以接受T的父类,但不能确定入参类型,只能接受null的传入 只能用于有限的方法,告诉编译器只能是T或其子类型,而返回只能使用Object类接收既不能用于入参,也不能用于返参

父类的静态方法能被子类重写吗? 不,父类的静态方法可以由子类继承,但不能由子类重写。即使子类中的静态方法与父类中的静态方法完全相同,也有两种完全不同的方法。

过程和线程的区别(问的很多,回答的时候用口语说,不要背书) 进程是cpu线程是资源分配的最小单位cpu调度最小单位。 该过程中的地址空间和其他资源不能在过程中共享资源。 一个过程可以有多个线程,可以打开过程或线程。 线程只能属于一个过程,线程可以直接使用同一过程的资源,线程依赖于过程。

final,finally,finalize的区别 final:修改、成员变量和成员方法不能继承,成员变量不能改变,成员方法不能重写 finally:与try...catch...共同使用,确保异常是否可调用 finalize:垃圾回收前会调用这种方法,子类可以重写finalize()实现资源回收的方法

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

静态属性和静态方法可以继承吗?可以重写吗?还有原因? 可继承 不可重写 而是被隐藏 如果静态方法和属性定义在子类中,则此时父类的静态方法或属性称为"隐藏"。如果你想通过父亲的名字直接调用父亲的静态方法和属性.完成方法或变量名。

了解成员内部、静态内部、局部内部和匿名内部,以及项目的应用 java中内部类主要分为成员内部类、局部内部类(嵌套在方法和作用域)、匿名内部类(无结构方法)、静态内部类(static不能使用任何外围类的非修饰类static成员变量和方法, 不依赖外围类) 使用内部类最吸引人的原因是,每个内部类都可以独立继承一个(接口)的实现,因此外围类是否继承了一个(接口)的实现对内部类没有影响。 因为Java不支持多继承,支持多接口的实现。但有时使用接口很难解决一些问题。此时,我们可以利用内部类提供的能力来解决这些程序设计问题,可以继承多个特定或抽象类别。可以说,接口只解决了一些问题,而内部类别使多重继承的解决方案更加完整。

string 转换成 integer方式和原理 String —>integer Intrger.parseInt(string); Integer—> string Integer.toString(); 原理: parseInt(String s)--内部调用parseInt(s,10)(默认为10进制) 正常判断null,进制范围,length等 判断第一个字符是否符号位置 循环遍历确定每个字符的十进制值 通过*= 和-= 计算拼接 判断是否为负值 返回结果。

垃圾回收机制将处理哪些情况下的对象? 1.没有活动线程访问所有实例。 2.循环引用的例子没有被任何其他例子访问。 3.Java 引用类型不同。实例是否符合垃圾收集条件取决于其引用类型。 要判断怎样的对象是没用的对象。这里有2种方法: 1.采用标记计数法: 标记内存中的对象。如果对象被引用一次,计数将增加1。如果引用被释放,计数将减少1。当计数为0时,对象可以回收。当然,这也导致了一个问题:循环引用的对象无法识别和回收。因此,有第二种方法: 2.采用根搜索算法: 从根开始,搜索所有可达对象,这样剩下的对象就需要回收了

静态代理和动态代理的区别是什么场景? 源代码由程序员创建或由特定工具自动生成,然后编译。在程序运行之前,代理.class文件已经存在。动态代理类:在程序运行过程中,采用反射机制动态创建。 场景:命名Spring框架、Hibernate框架等都是动态代理的例子

Java的异常体系 Throwable,Error,Exception

谈谈你对分析和分配的理解。 解析:Java中国方法调用的目标方法是Class常量池中的符号引用在文件中,在类加载的分析阶段,将部分符号引用转化为直接引用。这种分析的前提是,该方法在程序真正运行之前有一个确定的调用版本,该方法的调用版本在运行期间不能改变,即编译期可以知道,运行期不能改变。这种目标方法的调用称为分析(Resolve)。

只要能被invokestatic和invokespecial指令调用的方法可以在分析阶段确定唯一的调用版本,合格的静态方法(invokestatic指令)、私有方法、实例结构方法、父类方法(三)invokespecial指令),在类加载的分析阶段,将符号引用分析为该方法的直接引用。 分配:分配是多态性的体现,Java虚拟机底层为我们的开发提供了重载(Overload)“和重写”(Override)底层实现。重载属于静态分配,重写是动态分配的过程。 分析调用必须是一个静态过程,在编译期内完全确定。在类加载的分析阶段,所有涉及的符号引用将转换为可确定的直接引用,不会延迟到运行期。

Java实现多态的机制是么? 答:方法的重写Overriding和重载Overloading是Java多态性的不同表现 重写Overriding是父类与子类之间多态性的一种表现 重载Overloading是一个类中多态性的一种表现.

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

说说你对Java注解的理解 元注解 元注解的作用就是负责注解其他注解。java5.0的时候,定义了4个标准的meta-annotation类型,它们用来提供对其他注解的类型作说明。 1.@Target 2.@Retention 3.@Documented 4.@Inherited

Java中String的了解 在源码中string是用final 进行修饰,它是不可更改,不可继承的常量。

String为什么要设计成不可变的? 1、字符串池的需求 字符串池是方法区(Method Area)中的一块特殊的存储区域。当一个字符串已经被创建并且该字符串在 池 中,该字符串的引用会立即返回给变量,而不是重新创建一个字符串再将引用返回给变量。如果字符串不是不可变的,那么改变一个引用(如: string2)的字符串将会导致另一个引用(如: string1)出现脏数据。 2、允许字符串缓存哈希码 在java中常常会用到字符串的哈希码,例如: HashMap 。String的不变性保证哈希码始终一,因此,他可以不用担心变化的出现。 这种方法意味着不必每次使用时都重新计算一次哈希码——这样,效率会高很多。 3、安全 String广泛的用于java 类中的参数,如:网络连接(Network connetion),打开文件(opening files )等等。如果String不是不可变的,网络连接、文件将会被改变——这将会导致一系列的安全威胁。操作的方法本以为连接上了一台机器,但实际上却不是。由于反射中的参数都是字符串,同样,也会引起一系列的安全问题。

Object类的equal和hashCode方法重写,为什么? 首先equals与hashcode间的关系是这样的: 1、如果两个对象相同(即用equals比较返回true),那么它们的hashCode值一定要相同; 2、如果两个对象的hashCode相同,它们并不一定相同(即用equals比较返回false) 由于为了提高程序的效率才实现了hashcode方法,先进行hashcode的比较,如果不同,那没就不必在进行equals的比较了,这样就大大减少了equals比较的次数,这对比需要比较的数量很大的效率提高是很明显的

java的集合以及集合之间的继承关系

List,Set,Map的区别 Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。 Set接口主要实现了两个实现类:HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快 TreeSet :TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。 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)Map,Map中使用的对象也被允许释放: 这是为解决特殊问题设计的。如果没有map之外的引用指向某个“键”,则此“键”可以被垃圾收集器回收。

List和Set和Map的实现方式以及存储方式 List: 常用实现方式有:ArrayList和LinkedList ArrayList 的存储方式:数组,查询快 LinkedList的存储方式:链表,插入,删除快

Set: 常用实现方式有:HashSet和TreeSet HashSet的存储方式:哈希码算法,加入的对象需要实现hashcode()方法,快速查找元素 TreeSet的存储方式:按序存放,想要有序就要实现Comparable接口

附加: 集合框架提供了2个实用类:collections(排序,复制、查找)和Arrays对数组进行(排序,复制、查找)

Map: 常用实现方式有:HashMap和TreeMap HashMap的存储方式:哈希码算法,快速查找键值 TreeMap存储方式:对键按序存放

数组(如arryList)中数组容量不够了,怎么扩容? 在JDK1.7中如果通过无参构造的话,初始数组容量是0,当数组进行add()添加时,才真正的分配容量,通过位运算,每次按照1.5倍的比例扩容。 在JDK1.6中,初始数组容量为10,每次通过cope of方式扩容1.5倍+1.

HashMap的实现原理,如何put数据和get数据? 在JDK1.6,JDK1.7中,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个链表中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,HashMap采用位数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。 当链表数组的容量超过初始容量*加载因子(默认0.75)时,再散列将链表数组扩大2倍,把原链表数组的搬移到新的数组中。为什么需要使用加载因子?为什么需要扩容呢?因为如果填充比很大,说明利用的空间很多,如果一直不进行扩容的话,链表就会越来越长,这样查找的效率很低,扩容之后,将原来链表数组的每一个链表分成奇偶两个子链表分别挂在新链表数组的散列位置,这样就减少了每个链表的长度,增加查找效率。

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

取:

ArrayMap和HashMap的对比 1、存储方式不同 HashMap内部有一个HashMapEntry[]对象,每一个键值对都存储在这个对象里,当使用put方法添加键值对时,就会new一个HashMapEntry对象, 2、添加数据时扩容时的处理不一样,进行了new操作,重新创建对象,开销很大。ArrayMap用的是copy数据,所以效率相对要高。 3、ArrayMap提供了数组收缩的功能,在clear或remove后,会重新收缩数组,是否空间 4、ArrayMap采用二分法查找; List,Set,Map的区别 Set是最简单的一种集合。集合中的对象不按特定的方式排序,并且没有重复对象。 Set接口主要实现了两个实现类:HashSet: HashSet类按照哈希算法来存取集合中的对象,存取速度比较快 TreeSet :TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。

List的特征是其元素以线性方式存储,集合中可以存放重复对象。 ArrayList() : 代表长度可以改变得数组。可以对元素进行随机的访问,向ArrayList()中插入与删除元素的速度慢。 LinkedList(): 在实现中采用链表数据结构。插入和删除速度快,访问速度慢。

Map 是一种把键对象和值对象映射的集合,它的每一个元素都包含一对键对象和值对象。 Map没有继承于Collection接口 从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。 HashMap:Map基于散列表的实现。插入和查询“键值对”的开销是固定的。可以通过构造器设置容量capacity和负载因子load factor,以调整容器的性能。 LinkedHashMap: 类似于HashMap,但是迭代遍历它时,取得“键值对”的顺序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一点。而在迭代访问时发而更快,因为它使用链表维护内部次序。 TreeMap : 基于红黑树数据结构的实现。查看“键”或“键值对”时,它们会被排序(次序由Comparabel或Comparator决定)。TreeMap的特点在 于,你得到的结果是经过排序的。TreeMap是唯一的带有subMap()方法的Map,它可以返回一个子树。 WeakHashMap :弱键(weak key)Map,Map中使用的对象也被允许释放: 这是为解决特殊问题设计的。如果没有map之外的引用指向某个“键”,则此“键”可以被垃圾收集器回收。

HashMap和HashTable的区别 HashMap允许key和value为null; HashMap是非同步的,线程不安全,也可以通过Collections.synchronizedMap()方法来得到一个同步的HashMap HashMap存取速度更快,效率高 HashMap去掉了HashTable中的contains方法,加上了containsValue和containsKey方法

HashMap与HashSet的区别

HashSet与HashMap怎么判断集合元素重复? HashSet不能添加重复的元素,当调用add(Object)方法时候, 首先会调用Object的hashCode方法判hashCode是否已经存在,如不存在则直接插入元素;如果已存在则调用Object对象的equals方法判断是否返回true,如果为true则说明元素已经存在,如为false则插入元素。

集合Set实现Hash怎么防止碰撞 重写hashcode()和equles()方法

ArrayList和LinkedList的区别,以及应用场景 ArrayList是基于数组实现的,ArrayList线程不安全。 LinkedList是基于双链表实现的: 使用场景: (1)如果应用程序对各个索引位置的元素进行大量的存取或删除操作,ArrayList对象要远优于LinkedList对象; ( 2 ) 如果应用程序主要是对列表进行循环,并且循环时候进行插入或者删除操作,LinkedList对象要远优于ArrayList对象;

数组和链表的区别 数组:是将元素在内存中连续存储的;它的优点:因为数据是连续存储的,内存地址连续,所以在查找数据的时候效率比较高;它的缺点:在存储之前,我们需要申请一块连续的内存空间,并且在编译的时候就必须确定好它的空间的大小。在运行的时候空间的大小是无法随着你的需要进行增加和减少而改变的,当数据两比较大的时候,有可能会出现越界的情况,数据比较小的时候,又有可能会浪费掉内存空间。在改变数据个数时,增加、插入、删除数据效率比较低。 链表:是动态申请内存空间,不需要像数组需要提前申请好内存的大小,链表只需在用的时候申请就可以,根据需要来动态申请或者删除内存空间,对于数据增加和删除以及插入比数组灵活。还有就是链表中数据在内存中可以在任意的位置,通过应用来关联数据(就是通过存在元素的指针来联系)

堆和树的区别 节点的顺序 在二叉搜索树中,左子节点必须比父节点小,右子节点必须必比父节点大。但是在堆中并非如此。在最大堆中两个子节点都必须比父节点小,而在最小堆中,它们都必须比父节点大。

内存占用 普通树占用的内存空间比它们存储的数据要多。你必须为节点对象以及左/右子节点指针分配额外内存。堆仅仅使用一个数据来存储数组,且不使用指针。

平衡 二叉搜索树必须是“平衡”的情况下,其大部分操作的复杂度才能达到O(log n)。你可以按任意顺序位置插入/删除数据,或者使用 AVL 树或者红黑树,但是在堆中实际上不需要整棵树都是有序的。我们只需要满足对属性即可,所以在堆中平衡不是问题。因为堆中数据的组织方式可以保证O(log n) 的性能。

搜索 在二叉树中搜索会很快,但是在堆中搜索会很慢。在堆中搜索不是第一优先级,因为使用堆的目的是将最大(或者最小)的节点放在最前面,从而快速的进行相关插入、删除操作。

什么是深拷贝和浅拷贝 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

判断单链表成环与否? 使用快慢指针遍历链表: 慢指针: 从头节点开始,一次跳一个节点。 快指针: 从头节点开始,一次跳两个节点。 如果是成环的,这两个指针一定会相遇。

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

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

为什么要有线程,而不是仅仅用进程? 线程可以增加并发的程度啊。其实多进程也是可以并发,但是为什么要是线程呢?因为线程是属于进程的,是个轻量级的对象。所以再切换线程时只需要做少量的工作,而切换进程消耗很大。这是从操作系统角度讲。 从用户程序角度讲,有些程序在逻辑上需要线程,比如扫雷,它需要一个线程等待用户的输入,另一个线程的来更新时间。还有一个例子就是聊天程序,一个线程是响应用户输入,一个线程是响应对方输入。如果没有多线程,那么只能你说一句我说一句,你不说我这里就不能动,我还不能连续说。所以用户程序有这种需要,操作系统就要提供响应的机制

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

如何控制某个方法允许并发访问线程的个数? semaphore.acquire() 请求一个信号量,这时候的信号量个数-1(一旦没有可使用的信号量,也即信号量个数变为负数时,再次请求的时候就会阻塞,直到其他线程释放了信号量) semaphore.release() 释放一个信号量,此时信号量个数+1

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

谈谈wait/notify关键字的理解 等待对象的同步锁,需要获得该对象的同步锁才可以调用这个方法,否则编译可以通过,但运行时会收到一个异常:IllegalMonitorStateException。 调用任意对象的 wait() 方法导致该线程阻塞,该线程不可继续执行,并且该对象上的锁被释放。 唤醒在等待该对象同步锁的线程(只唤醒一个,如果有多个在等待),注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。 调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。

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

线程如何关闭? 一种是调用它里面的stop()方法 另一种就是你自己设置一个停止线程的标记 (推荐这种)

讲一下java中的同步的方法(另一种问法:数据一致性如何保证?) 1.即有synchronized关键字修饰的方法。 2.同步代码块(如:双重判断的单例模式) 3.使用特殊域变量(volatile)实现线程同步 4.使用重入锁实现线程同步 5.使用局部变量实现线程同步

如何保证线程安全? 1.synchronized; 2.Object方法中的wait,notify; 3.ThreadLocal机制 来实现的。

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

两个进程同时要求写或者读,能不能实现?如何防止进程的同步? 可以实现的。 同步方式有: 互斥锁、条件变量、读写锁、记录锁(文件锁)和信号灯

线程间操作List List list = Collections.synchronizedList(new ArrayList());

Synchronized用法及原理 用法:修饰静态方法、实例方法、代码块 原理:不是一两句话能说清,建议去深入了解一下。

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

static synchronized 方法的多线程访问和作用 1.synchronized static是某个类的范围,synchronized static cSync{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。

2.synchronized 是某实例的范围,synchronized isSync(){}防止多个线程同时访问这个实例中的synchronized 方法。

同一个类里面两个synchronized方法,两个线程同时访问的问题 同一个object中多个方法都加了synchronized关键字的时候,其中调用任意方法之后需等该方法执行完成才能调用其他方法,即同步的,阻塞的; 此结论同样适用于对于object中使用synchronized(this)同步代码块的场景; synchronized锁定的都是当前对象!

volatile的作用,原理,性能。 作用:1、保持内存可见性 2、防止指令重排 原理:获取JIT(即时Java编译器,把字节码解释为机器语言发送给处理器)的汇编代码,发现volatile多加了lock addl指令,这个操作相当于一个内存屏障,使得lock指令后的指令不能重排序到内存屏障前的位置。这也是为什么JDK1.5以后可以使用双锁检测实现单例模式。 lock前缀的另一层意义是使得本线程工作内存中的volatile变量值立即写入到主内存中,并且使得其他线程共享的该volatile变量无效化,这样其他线程必须重新从主内存中读取变量值。 性能:读操作与普通变量无差别,写操作会慢一些,大多情况比锁消耗低。

谈谈NIO的理解 如果问到这个,很容易就会问到和IO的比较,所以可以直接看看这个。https://www.cnblogs.com/lingqin/p/11324502.html

synchronized 和volatile 关键字的区别 1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。 2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的 3.volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性 4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。 5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

synchronized与Lock的区别及使用场景 synchronized原始采用的是CPU悲观锁机制,即线程获得的是独占锁。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁。而在CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低; 而Lock用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就是CAS操作(Compare and Swap)。我们可以进一步研究ReentrantLock的源代码,会发现其中比较重要的获得锁的一个方法是compareAndSetState。这里其实就是调用的CPU提供的特殊指令。 使用场景:在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争),此时Lock的性能要远远优于synchronized。所以说,在具体使用时要根据适当情况选择。

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

死锁的四个必要条件?怎么避免死锁? 死锁产生的原因

  1. 系统资源的竞争 系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁。
  2. 进程运行推进顺序不合适 互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。 请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。 不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。 循环等待条件: 若干进程间形成首尾相接循环等待资源的关系 这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。 死锁的避免与预防: 死锁避免的基本思想: 系统对进程发出每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,如果分配后系统可能发生死锁,则不予分配,否则予以分配。这是一种保证系统不进入死锁状态的动态策略。 理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何让这四个必要条件不成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源。因此,对资源的分配要给予合理的规划。 死锁避免和死锁预防的区别: 死锁预防是设法至少破坏产生死锁的四个必要条件之一,严格的防止死锁的出现,而死锁避免则不那么严格的限制产生死锁的必要条件的存在,因为即使死锁的必要条件存在,也不一定发生死锁。死锁避免是在系统运行过程中注意避免死锁的最终发生。

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

谈谈对多线程的理解 线程是由一个主线程和很多个子线程组成的,主线程消失,子线程也会消失,但是子线程消失其中一个主线程不会消失 线程的生命周期分为5个步骤像人的一生一样,这5个步骤分别对应了5个方法 新生-->启动-->运行-->阻塞-->销毁 继承Thread类or实现runnable方法-->start-->run-->sleep(睡眠)or wait(挂起)-->destroy

多线程有什么要注意的问题? 给线程起有意义的名字,这样方便找Bug 缩小同步范围,从而减少锁的争用,例如对于 synchronized,应该尽量使用同步块而不是同步方法 多用同步工具少用 wait() 和 notify()。首先,CountDownLatch, CyclicBarrier, Semaphore 和Exchanger 这些同步类简化了编码操作,而用 wait() 和 notify() 很难实现复杂控制流;其次,这些同步类是由最好的企业编写和维护,在后续的 JDK 中还会不断优化和完善。 使用BlockingQueue实现生产者消费者问题 多用并发集合少用同步集合,例如应该使用 ConcurrentHashMap 而不是 Hashtable 使用本地变量和不可变类来保证线程安全 使用线程池而不是直接创建线程,这是因为创建线程代价很高,线程池可以有效地利用有限的线程来启动任务

自己去设计网络请求框架,怎么做? 这种并没有一个完全正确的答案,看个人的思路与理解

okhttp源码 自己看一遍源码即可,最好能够手写出他的流程。

从网络加载一个10M的图片,说下注意事项 图片缓存、异常恢复、质量压缩,从这几方面说就好了

TCP的3次握手和四次挥手 三次握手: 第一次:客户端发送请求到服务器,服务器知道客户端发送,自己接收正常。SYN=1,seq=x 第二次:服务器发给客户端,客户端知道自己发送、接收正常,服务器接收、发送正常。ACK=1,ack=x+1,SYN=1,seq=y 第三次:客户端发给服务器:服务器知道客户端发送,接收正常,自己接收,发送也正常.seq=x+1,ACK=1,ack=y+1

四次挥手: 第一次:客户端请求断开FIN,seq=u 第二次:服务器确认客户端的断开请求ACK,ack=u+1,seq=v 第三次:服务器请求断开FIN,seq=w,ACK,ack=u+1 第四次:客户端确认服务器的断开ACK,ack=w+1,seq=u+1

为什么连接的时候是三次握手,关闭的时候却是四次握手? 因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,"你发的FIN报文我收到了"。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

为什么不能用两次握手进行连接? 3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。 现在把三次握手改成仅需要两次握手,死锁是可能发生的。

为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态? 虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可以最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

TCP与UDP的区别 tcp是面向连接的,由于tcp连接需要三次握手,所以能够最低限度的降低风险,保证连接的可靠性。 udp 不是面向连接的,udp建立连接前不需要与对象建立连接,无论是发送还是接收,都没有发送确认信号。所以说udp是不可靠的。 由于udp不需要进行确认连接,使得UDP的开销更小,传输速率更高,所以实时行更好。

TCP与UDP的应用 从特点上我们已经知道,TCP 是可靠的但传输速度慢 ,UDP 是不可靠的但传输速度快。因此在选用具体协议通信时,应该根据通信数据的要求而决定。  若通信数据完整性需让位与通信实时性,则应该选用 TCP 协议(如文件传输、重要状态的更新等);反之,则使用 UDP 协议(如视频传输、实时通信等)。

Http https区别,此处延伸:https的实现原理 1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。 2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。 3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。 4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。 https实现原理: (1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。 (2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。 (3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。 (4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。 (5)Web服务器利用自己的私钥解密出会话密钥。 (6)Web服务器利用会话密钥加密与客户端之间的通信。 7、Http位于TCP/IP模型中的第几层?为什么说Http是可靠的数据传输协议? tcp/ip的五层模型: 从下到上:物理层->数据链路层->网络层->传输层->应用层 其中tcp/ip位于模型中的网络层,处于同一层的还有ICMP(网络控制信息协议)。http位于模型中的应用层 由于tcp/ip是面向连接的可靠协议,而http是在传输层基于tcp/ip协议的,所以说http是可靠的数据传输协议。

8、HTTP链接的特点 HTTP连接最显著的特点是客户端发送的每次请求都需要服务器回送响应,在请求结束后,会主动释放连接。 从建立连接到关闭连接的过程称为“一次连接”。

HTTP报文结构 一个HTTP请求报文由四个部分组成:请求行、请求头部、空行、请求数据。 1.请求行 请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。比如 GET /data/info.html HTTP/1.1 2.请求头部 HTTP客户程序(例如浏览器),向服务器发送请求的时候必须指明请求类型(一般是GET或者 POST)。如有必要,客户程序还可以选择发送其他的请求头。大多数请求头并不是必需的,但Content-Length除外。对于POST请求来说 Content-Length必须出现。 3.空行 它的作用是通过一个空行,告诉服务器请求头部到此为止。 4.请求数据 若方法字段是GET,则此项为空,没有数据。若方法字段是POST,则通常来说此处放置的就是要提交的数据

HTTP与HTTPS的区别以及如何实现安全性 区别:http是明文传输,传输的数据很可能被中间节点获取,从而导致数据传输不安全  https是加密传输,可以保证数据的传输安全 如何实现:http是应用层协议,它会将要传输的数据以明文的方式给传输层,这样显然不安全。https则是在应用层与传输层之间又加了一层,该层遵守SSL/TLS协议,用于数据加密。

如何验证证书的合法性? 1、证书是否是信任的有效证书。所谓信任:浏览器内置了信任的根证书,就是看看web服务器的证书是不是这些信任根发的或者信任根的二级证书机构颁发的。所谓有效,就是看看web服务器证书是否在有效期,是否被吊销了。2、对方是不是上述证书的合法持有者。简单来说证明对方是否持有证书的对应私钥。验证方法两种,一种是对方签个名,我用证书验证签名;另外一种是用证书做个信封,看对方是否能解开。以上的所有验证,除了验证证书是否吊销需要和CA关联,其他都可以自己完成。验证正式是否吊销可以采用黑名单方式或者OCSP方式。黑名单就是定期从CA下载一个名单列表,里面有吊销的证书序列号,自己在本地比对一下就行。优点是效率高。缺点是不实时。OCSP是实时连接CA去验证,优点是实时,缺点是效率不高。

client如何确定自己发送的消息被server收到? HTTP协议里,有请求就有响应,根据响应的状态吗就能知道。

HttpClient与HttpUrlConnection的区别 (此处延伸:Volley里用的哪种请求方式(2.3前HttpClient,2.3后HttpUrlConnection) 首先HttpClient和HttpUrlConnection 这两种方式都支持Https协议,都是以流的形式进行上传或者下载数据,也可以说是以流的形式进行数据的传输,还有ipv6,以及连接池等功能。HttpClient这个拥有非常多的API,所以如果想要进行扩展的话,并且不破坏它的兼容性的话,很难进行扩展,也就是这个原因,Google在Android6.0的时候,直接就弃用了这个HttpClient. 而HttpUrlConnection相对来说就是比较轻量级了,API比较少,容易扩展,并且能够满足Android大部分的数据传输。比较经典的一个框架volley,在2.3版本以前都是使用HttpClient,在2.3以后就使用了HttpUrlConnection。

WebSocket与socket的区别 1.WebSocket protocol 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。 2.Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把... 3.区别 Socket是传输控制层协议,WebSocket是应用层协议。

谈谈你对安卓签名的理解。 每个应用都必须签名 应用可以被不同的签名文件签名(如果有源代码或者反编译后重新编译) 同一个应用如果签名不同则不能覆盖安装

请解释安卓为啥要加签名机制? 发送者的身份认证:由于开发商可能通过使用相同的 Package Name 来混淆替换已经安装的程序,以此保证签名不同的包不被替换 保证信息传输的完整性:签名对于包中的每个文件进行处理,以此确保包中内容不被替换 防止交易中的抵赖发生:Market(应用市场)对软件的要求

视频加密传输 DES加密。用java中提供的加密包。 将视频文件的数据流前100个字节中的每个字节与其下标进行异或运算。解密时只需将加密过的文件再进行一次异或运算即可。

App 是如何沙箱化,为什么要这么做? 在Android系统中,应用(通常)都在一个独立的沙箱中运行,即每一个Android应用程序都在它自己的进程中运行,都拥有一个独立的Dalvik虚拟机实例。Dalvik经过优化,允许在有限的内存中同时高效地运行多个虚拟机的实例,并且每一个Dalvik应用作为一个独立的Linux进程执行。Android这种基于Linux的进程“沙箱”机制,是整个安全设计的基础之一。 Android扩展了Linux内核安全模型的用户与权限机制,将多用户操作系统的用户隔离机制巧妙地移植为应用程序隔离。将UID(一个用户标识)不同的应用程序自然形成资源隔离,如此便形成了一个操作系统级别的应用程序“沙箱”。

(2)Android面试题(基础+进阶)(必须)

四大组件是什么(这个不知道的话,没必要去面试了,转行吧) Android四大组件有Activity,Service服务,Content Provider内容提供,BroadcastReceiver。

四大组件的生命周期和简单用法 activity:onCreate() -> onStart() -> onResume() -> onPause() -> onStop() -> onDetroy() Service: service 启动方式有两种,一种是通过startService()方式进行启动,另一种是通过bindService()方式进行启动。不同的启动方式他们的生命周期是不一样. 通过startService()这种方式启动的service,生命周期是这样:调用startService() --> onCreate()--> onStartConmon()--> onDestroy()。这种方式启动的话,需要注意一下几个问题,第一:当我们通过startService被调用以后,多次在调用startService(),onCreate()方法也只会被调用一次,而onStartConmon()会被多次调用当我们调用stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当我们通过startService启动时候,通过intent传值,在onStartConmon()方法中获取值的时候,一定要先判断intent是否为null。 通过bindService()方式进行绑定,这种方式绑定service,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 这种方式进行启动service好处是更加便利activity中操作service,比如加入service中有几个方法,a,b ,如果要在activity中调用,在需要在activity获取ServiceConnection对象,通过ServiceConnection来获取service中内部类的类对象,然后通过这个类对象就可以调用类中的方法,当然这个类需要继承Binder对象 contentProvider:contentProvider的生命周期、理解应该跟进程一样,它作为系统应用组件、其生命周期应该跟app应用的生命周期类似,只是它属于系统应用、所以随系统启动而初始化,随系统关机而结束;但也存在其他状态下结束进程、比如说系统内存不够时,进行内存回收、会根据生成时间态、用户操作等情况进行是否内存回收。 BroadcastReceiver:广播的生命周期从调用开始到onReceiver执行完毕结束,需要注意的是,一般广播的生命周期都极短,需要在10s内处理完onReceiver中的所有工作,所以,一般不进行耗时长的工作,如果有耗时长的工作,应当通过Intent传递给Service进行处理。(注意,不要在onReceiver中开启线程进行耗时任务处理,否则,在10s后,该线程会变成空线程,从而导致任务的丢失。同样的,也不要使用bindService来绑定服务。) 值得注意的是,如果是在代码中动态注册的广播,如:在Activity注册,那么在Activity的onDestory中需要使用unregisterReceiver注销广播。

Activity之间的通信方式 Intent 借助类的静态变量 借助全局变量/Application 借助外部工具  借助SharedPreference  使用Android数据库SQLite  赤裸裸的使用File  Android剪切板 借助Service

横竖屏切换的时候,Activity 各种情况下的生命周期 分两种情况: 1.不设置Activity的android:configChanges,或设置Activity的android:configChanges="orientation",或设置Activity的android:configChanges="orientation|keyboardHidden",切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次。 横竖屏切换造成 activity 的生命周期 onPause()-onSaveInstanceState()-onStop()-onDestroy()-onCreat()-onStart()-onRestoreInstanceState()-onResume()即会导致 activity 的销毁和重建 。

2.配置 android:configChanges="orientation|keyboardHidden|screenSize",才不会销毁 activity,且只调用 onConfigurationChanged方法。 onSaveInstanceState() 与onRestoreIntanceState() 资源相关的系统配置发生改变或者资源不足时(例如屏幕旋转),当前 Activity 会销毁,并且在 onStop 之前回调 onSaveInstanceState 保存数据,在重新创建 Activity 的时候在onStart 之后回调 onRestoreInstanceState。其中 Bundle 数据会传到 onCreate(不一定有数据)和 onRestoreInstanceState(一定有数据)。 用户或者程序员主动去销毁一个 Activity 的时候不会回调(如代码中 finish()或用户按下 back,不会回调),其他情况都会调用,来保存界面信息。

Activity与Fragment之间生命周期比较 a. 在创建的过程中,是 Activity 带领 Fragment 执行生命周期的方法,所以它们生命周期执行的顺序如下:
 Activity -- onCreate() , Fragment -- onAttach() -> onCreate() -> onCreateView() -> onActivityCreated

.

Activity -- onStart() 
Fragment -- onStart()


Activity -- onResume()
 Fragment -- onResume()


最后,在销毁时是 Fragment 带领 Activity 执行生命周期的方法:
 Fragment -- onPause()
 Activity -- onPause()


Fragment -- onStop()
 Activity -- onStop()


Fragment -- onDestroyView() -> onDestroy() -> onDetach()
 Activity -- onDestroy()

Activity上有Dialog的时候按Home键时的生命周期 有 Dialog 和 无 Dialog 按 Home 键效果一样:

  1. 正常启动: onCreate() -> onStart() -> onResume()
  2. 按 home 键: onPause() -> onStop()
  3. 再次启动: onRestart() -> onStart() -> onResume()

两个Activity 之间跳转时必然会执行的是哪几个方法? a. 正常情况下 Activity A 跳转到 Activity B 时: A调用 onCreate() 方法 -> onStart() 方法 -> onResume() 方法,此时 A 前台可见。当 A 跳转到 B 时,A 调用 onPause() 方法,然后调用新的 Activity B 中的 onCreate() 方法 -> onStart() 方法 -> onResume() 方法。最后 A 再调用onStop()方法。 b. 当 Activity B 为透明主题时: 除了最后 Activity A 不调用 onStop() 方法之外,其它都和 a 中的一样。

Activity的四种启动模式对比 此处延伸:栈(First In Last Out)与队列(First In First Out)的区别 区别:队列先进先出,栈先进后出 对插入和删除操作的"限定"。 栈是限定只能在表的一端进行插入和删除操作的线性表。 队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。 遍历数据速度不同

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。

Activity状态保存于恢复 当 Activity 在异常情况( 系统内存不足或者系统配置发生了改变等 )被销毁重建后, 在销毁的时候 Activity 会调用 onSaveInstanceState() 方法用于保存 Activity 相关的状态和数据,然后在重建后的 Activity 的中我们可以通过 onCreate() 或者 onRestoreInstanceState() 方法恢复数据,这里我们需要注意的是如果通过 onCreate() 方法恢复,那么得先判断它的 intent 参数 是否为空,如果在 onRestoreInstanceState() 方法恢复就不会,因为只要 onRestoreInstanceState() 方法被调用就说明一定有数据,不会为空。Google 推荐使用 onRestoreInstanceState() 方法。

如何实现Fragment的滑动? 将Fragment与viewpager绑定,通过viewpager中的touch事件,会进行move事件的滑动处理。

fragment之间传递数据的方式? 1、在fragment中设置一个方法,然后进行调用 2、采取接口回调的方式进行数据传递。 3、广播或者是使用三方开源框架:EventBus

Activity 怎么和Service 绑定?怎么在Activity 中启动自己对应的Service? 1、activity能进行绑定得益于Serviece的接口。为了支持Service的绑定,实现onBind方法。 2、Service和Activity的连接可以用ServiceConnection来实现。需要实现一个新的ServiceConnection,重现onServiceConnected和OnServiceDisconnected方法,一旦连接建立,就能得到Service实例的引用。 3、执行绑定,调用bindService方法,传入一个选择了要绑定的Service的Intent(显示或隐式)和一个你实现了的ServiceConnection的实例

service和activity怎么进行数据交互? 1.通过 broadcast:通过广播发送消息到 activitry 2.通过 Binder:通过与 activity 进行绑定 (1)添加一个继承 Binder 的内部类,并添加相应的逻辑方法。 (2)重写 Service 的 onBind 方法,返回我们刚刚定义的那个内部类实例。 (3)Activity 中创建一个 ServiceConnection 的匿名内部类,并且 重 写 里 面 的 onServiceConnected 方 法 和onServiceDisconnected 方法,这两个方法分别会在活动与服务成功绑定以及解除绑定的时候调用(在onServiceConnected方法中,我们可以得到一个刚才那个 service 的 binder 对象,通过对这个 binder 对象进行向下转型,得到我们那个自定义的 Binder 实例,有了这个实例,做可以调用这个实例里面的具体方法进行需要的操作了)。

Service的开启方式,请描述一下Service 的生命周期,请描述一下Service 的生命周期 service 启动方式有两种,一种是通过startService()方式进行启动,另一种是通过bindService()方式进行启动。不同的启动方式他们的生命周期是不一样. 通过startService()这种方式启动的service,生命周期是这样:调用startService() --> onCreate()--> onStartConmon()--> onDestroy()。这种方式启动的话,需要注意一下几个问题,第一:当我们通过startService被调用以后,多次在调用startService(),onCreate()方法也只会被调用一次,而onStartConmon()会被多次调用当我们调用stopService()的时候,onDestroy()就会被调用,从而销毁服务。第二:当我们通过startService启动时候,通过intent传值,在onStartConmon()方法中获取值的时候,一定要先判断intent是否为null。 通过bindService()方式进行绑定,这种方式绑定service,生命周期走法:bindService-->onCreate()-->onBind()-->unBind()-->onDestroy() bingservice 这种方式进行启动service好处是更加便利activity中操作service,比如加入service中有几个方法,a,b ,如果要在activity中调用,在需要在activity获取ServiceConnection对象,通过ServiceConnection来获取service中内部类的类对象,然后通过这个类对象就可以调用类中的方法,当然这个类需要继承Binder对象

请描述一下广播BroadcastReceiver的理解 广播,是一个全局的监听器,属于Android四大组件之一。Android 广播分为两个角色:广播发送者、广播接收者。作用是监听 / 接收 应用 App 发出的广播消息,并 做出响应 可应用在: Android不同组件间的通信(含 :应用内 / 不同应用之间) 多线程通信 与 Android 系统在特定情况下的通信 如:电话呼入时、网络可用时

Broadcast注册方式与区别 (此处延伸:什么情况下用动态注册) Broadcast广播,注册方式主要有两种. 第一种是静态注册,也可成为常驻型广播,这种广播需要在Androidmanifest.xml中进行注册,这中方式注册的广播,不受页面生命周期的影响,即使退出了页面,也可以收到广播这种广播一般用于想开机自启动啊等等,由于这种注册的方式的广播是常驻型广播,所以会占用CPU的资源。 第二种是动态注册,而动态注册的话,是在代码中注册的,这种注册方式也叫非常驻型广播,收到生命周期的影响,退出页面后,就不会收到广播,我们通常运用在更新UI方面。这种注册方式优先级较高。最后需要解绑,否会会内存泄露 广播是分为有序广播和无序广播。

在manifest 和代码中如何注册和使用BroadcastReceiver?           

本地广播和全局广播有什么差别? BroadcastReceiver是针对应用间、应用与系统间、应用内部进行通信的一种方式 LocalBroadcastReceiver仅在自己的应用内发送接收广播,也就是只有自己

标签: dx4电量变送器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台