码个蛋(codeegg) 第 802 次推文
码妞看世界
一墙爬山虎
1. 谈谈冷启动与热启动
app冷启动: 当应用启动时, 后台没有该应用的进程 ,这时系统会重新创建一个新的进程分配给该应用,这个启动方式就叫做冷启动((后台不存在该应用进程) 冷启动因为系统会重新创建一个新的进程分配给它,所以会 先创建和初始化Application 类, 再创建和初始化MainActivity类 (包括一系列的测量、布局、绘制),最后显示在界面上。 app热启动: 当 应用已经被打开 ,但是被按下返回键、Home键等按键时回到桌面或者是其他程序的时候,再重新打开该app时,这个方式叫做热启动(后台已经存在该应用进程)。 热启动因为会 从已有的进程中来启动 ,所以热启动就 不会走Application 这步了,而是 直接走MainActivity (包括一系列的测量、布局、绘制),所以热启动的过程只需要创建和初始化一个MainActivity就行了,而不必创建和初始化Application。 冷启动的流程 当点击app的启动图标时,安卓系统会从 Zygote 进程中fork创建出一个新的进程分配给该应用,之后会依次创建和初始化 Application 类、创建 MainActivity 类、加载主题样式 Theme 中的 windowBackground 等属性设置给MainActivity以及配置Activity层级上的一些属性、再 inflate 布局、当 onCreate/onStart/onResume 方法都走完了后最后才进行 contentView 的 measure/layout/draw 显示在界面上。 冷启动的生命周期简要流程: Application构造方法 –> attachBaseContext() –> onCreate –> Activity构造方法 –> onCreate() –> 配置主体中的背景等操作 –> onStart() –> onResume() –> 测量、布局、绘制显示 冷启动的优化 主要是 视觉上的优化 ,解决白屏问题,提高用户体验,所以通过上面冷启动的过程。 能做的优化如下: 1) 减少 onCreate()方法的工作量 2) 不要让 Application 参与业务的操作 3) 不要在 Application 进行耗时操作 4) 不要以静态变量的方式在 Application 保存数据 5) 减少布局的复杂度和层级 6) 减少主线程耗时2. XML文档定义有几种形式?它们之间有何本质区别?
解析XML文档有哪几种方式?
XML文档定义分为DTD和Schema两种形式;二者都是对XML语法的约束,其本质区别在于Schema本身也是一个XML文件,可以被XML解析器解析,而且可以为XML承载的数据定义类型,约束能力较之DTD更强大。
对XML的解析主要有:
DOM(文档对象模型,Document Object Model)、SAX(Simple API for XML)和StAX(Java 6中引入的新的解析XML的方式,Streaming API for XML),其中DOM处理大型文件时其性能下降的非常厉害,这个问题是由DOM树结构占用的内存较多造成的,而且DOM解析方式必须在解析文件之前把整个文档装入内存,适合对XML的随机访问(典型的用空间换取时间的策略);
SAX是事件驱动型的XML解析方式,它顺序读取XML文件,不需要一次全部装载整个文件。
当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过事件回调代码来处理XML文件,适合对XML的顺序访问;顾名思义,StAX把重点放在流上,实际上StAX与其他解析方式的本质区别就在于应用程序能够把XML作为一个事件流来处理。
将XML作为一组事件来处理的想法并不新颖(SAX就是这样做的),但不同之处在于StAX允许应用程序代码把这些事件逐个拉出来,而不用提供在解析器方便时从解析器中接收事件的处理程序。
3. Java nio 和 io 的区别
Java NIO提供了与标准IO不同的IO工作方式:
Channels and Buffers(通道和缓冲区):
标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
Asynchronous IO(异步IO):
Java NIO可以让你异步的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似
Selectors(选择器):
Java NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
阻塞IO和非阻塞IO
Java IO流都是阻塞的,这意味着,当一条线程执行read()或者write()方法时,这条线程会一直阻塞直到读取到了一些数据或者要写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情。
java NIO的非阻塞模式(Java NIO有阻塞模式和非阻塞模式,阻塞模式的NIO除了使用Buffer存储数据外和IO基本没有区别)允许一条线程从channel中读取数据,通过返回值来判断buffer中是否有数据,如果没有数据,NIO不会阻塞,因为不阻塞这条线程就可以去做其他的事情,过一段时间再回来判断一下有没有数据。NIO的写也是一样的,一条线程将buffer中的数据写入channel,它不会等待数据全部写完才会返回,而是调用完write()方法就会继续向下执行
面向流与面向缓冲
Java IO和NIO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。
此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
4. String 为什么要设计成不可变的
1、字符串池的需求字符串池是方法区(Method Area)中的一块特殊的存储区域。当一个字符串已经被创建并且该字符串在池中,该字符串的引用会立即返回给变量,而不是重新创建一个字符串再将引用返回给变量。如果字符串不是不可变的,那么改变一个引用(如: string2)的字符串将会导致另一个引用(如: string1)出现脏数据。
2、允许字符串缓存哈希码在 java 中常常会用到字符串的哈希码,例如:HashMap 。String 的不变性保证哈希码始终一,因此,他可以不用担心变化的出现。这种方法意味着不必每次使用时都重新计算一次哈希码——这样,效率会高很多。
3、安全 String 广泛的用于 java 类中的参数,如:网络连接(Network connetion),打开文件(opening files )等等。如果 String 不是不可变的,网络连接、文件将会被改变——这将会导致一系列的安全威胁。操作的方法本以为连接上了一台机器,但实际上却不是。由于反射中的参数都是字符串,同样,也会引起一系列的安全问题。
5. HashMap 排序
已知一个 HashMap集合, User 有 name(String)和 age(int)属性。请写一个方法 实现对HashMap的排序功能 ,要求对HashMap中的User的age倒序进行 排序 。 Tips : HashMap 本身就是不可排序的 ,但是该道题偏偏让给HashMap排序,那我们就得想在API 中有没有这样的Map 结构是有序的, LinkedHashMap ,对,就是他,他是Map 结构,也是链表结构,有序的,更可喜的是他是HashMap 的子类,我们返回LinkedHashMap即可。 但凡是 对集合的操作 ,我们应该保持一个原则就是 能用JDK中的API就用JDK中的API ,比如排序算法我们不应该去用冒泡或者选择 , 而 是首先想到用 Collections 集合工具类 。public class HashMapTest { public static void main(String[] args) { HashMap users = new HashMap<>(); users.put(1, new User("张三", 25)); users.put(3, new User("李四", 22)); users.put(2, new User("王五", 28)); System.out.println(users); HashMap sortHashMap = sortHashMap(users); System.out.println(sortHashMap); /** * 控制台输出内容 * {1=User [name=张三, age=25], 2=User [name=王五, age=28], 3=User [name=李四, age=22]} * {2=User [name=王五, age=28], 1=User [name=张三, age=25], 3=User [name=李四, age=22]} */ } public static HashMap sortHashMap(HashMapmap) { // 首先拿到 map 的键值对集合 Set> entrySet = map.entrySet(); // 将 set 集合转为 List 集合,为什么,为了使用工具类的排序方法 List> list = new ArrayList>(entrySet); // 使用 Collections 集合工具类对 list 进行排序,排序规则使用匿名内部类来实现 Collections.sort(list, new Comparator>() { @Override public int compare(Entry o1, Entry o2) { //按照要求根据 User 的 age 的倒序进行排 return o2.getValue().getAge()-o1.getValue().getAge(); } }); //创建一个新的有序的 HashMap 子类的集合 LinkedHashMap linkedHashMap = new LinkedHashMap(); //将 List 中的数据存储在 LinkedHashMap 中 for(Entry entry : list){ linkedHashMap.put(entry.getKey(), entry.getValue()); } return linkedHashMap; }}
相关文章:
继腾讯之后,又有大佬向Flutter热更新动手啦
APP 定位过于频繁,我用反射 + 动态代理揪出元凶
老板说:App启动必须加速35%!
今日问题:
发过好几篇面试题,这样的形式对你帮助大吗?
专属升级社区:《这件事情,我终于想明白了》